bzoj2245: [SDOI2011]工作安排

时间:2023-03-08 21:31:16

费用流。

这道题的模型比较明显,拆点也是很容易看出来的。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1000 + 10;
const int maxm = 500000 + 10;
const int inf = 0x3f3f3f3f;
int g[maxn],v[maxm],f[maxm],c[maxm],next[maxm],eid;
int idn[maxn],idm[maxn];
int a[maxn][5];
int n,m,S,T,vid,u;
int d[maxn],pre[maxn];
int q[maxn],l,r;
bool inque[maxn]; void addedge(int a,int b,int F,int C) {
v[eid]=b; f[eid]=F; c[eid]=C; next[eid]=g[a]; g[a]=eid++;
v[eid]=a; f[eid]=0; c[eid]=-C; next[eid]=g[b]; g[b]=eid++;
} void build() {
memset(g,-1,sizeof(g));
scanf("%d%d",&n,&m);
S=1; T=2;
vid=2;
for(int i=1,t;i<=m;i++) {
idm[i]=++vid;
scanf("%d",&t);
addedge(S,idm[i],t,0);
}
for(int i=1;i<=n;i++) {
idn[i]=++vid;
for(int j=1,t;j<=m;j++) {
scanf("%d",&t);
if(t==1) addedge(idm[j],idn[i],inf,0);
}
}
for(int i=1,t;i<=n;i++) {
scanf("%d",&t);
for(int j=1;j<=t;j++) scanf("%d",&a[j][1]);
a[t+1][1]=inf;
for(int j=1;j<=t+1;j++) scanf("%d",&a[j][2]);
for(int j=1;j<=t+1;j++)
addedge(idn[i],T,a[j][1]-a[j-1][1],a[j][2]);
}
} bool SPFA() {
memset(d,0xe3f,sizeof(d));
d[S]=0; l=r=0;
inque[q[r++]=S]=1;
while(l<r) {
inque[u=q[l++]]=0;
for(int i=g[u];~i;i=next[i]) if(f[i] && d[v[i]]>d[u]+c[i]) {
d[v[i]]=d[u]+c[i];
pre[v[i]]=i;
if(!inque[v[i]]) {
inque[q[r++]=v[i]]=1;
}
}
}
return d[T]<inf;
} int augment() {
int aug=inf,res=0;
for(int i=T;i!=S;i=v[pre[i]^1]) {
aug=min(aug,f[pre[i]]);
}
for(int i=T;i!=S;i=v[pre[i]^1]) {
f[pre[i]]-=aug;
f[pre[i]^1]+=aug;
res+=c[pre[i]]*aug;
}
return res;
} void solve() {
long long res=0;
while(SPFA()) res+=augment();
printf("%lld\n",res);
} int main() {
build();
solve();
return 0;
}