【bzoj2245】 SDOI2011—工作安排
http://www.lydsy.com/JudgeOnline/problem.php?id=2245 (题目链接)
题意
n个产品,每个需要造C[i]件;m个员工,每个员工可以制造一些产品;每个员工的愤怒值是关于制造产品数的递增分段函数。所有员工的愤怒值之和最少是多少。
Solution
按照题意连边构图,跑费用即可。
细节
开LL。
代码
// bzoj2245 #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<queue> #define LL long long #define inf 2147483640 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=100010; struct edge {int from,to,next,w,c;}e[maxn*10]; int p[maxn],f[maxn],d[maxn],head[maxn],vis[maxn],s[maxn],T[300][300],w[300][300]; int n,m,cnt=1,es,et; void link(int u,int v,int w,int c) { e[++cnt]=(edge){u,v,head[u],w,c};head[u]=cnt; e[++cnt]=(edge){v,u,head[v],0,-c};head[v]=cnt; } LL SPFA() { queue<int> q; memset(f,0,sizeof(f)); memset(d,0x7f,sizeof(d)); q.push(es);d[es]=0;f[es]=inf; while (!q.empty()) { int x=q.front();q.pop();vis[x]=0; for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]>d[x]+e[i].c) { d[e[i].to]=d[x]+e[i].c; f[e[i].to]=min(f[x],e[i].w); p[e[i].to]=i; if (!vis[e[i].to]) q.push(e[i].to),vis[e[i].to]=1; } } if (f[et]==0) return 0; for (int i=p[et];i;i=p[e[i].from]) e[i].w-=f[et],e[i^1].w+=f[et]; return (LL)f[et]*d[et]; } LL EK() { LL ans=0; while (1) { LL x=SPFA(); if (x==0) return ans; ans+=x; } } int main() { scanf("%d%d",&m,&n); es=10000;et=es+1; for (int x,i=1;i<=n;i++) { scanf("%d",&x); link(i+m,et,x,0); } for (int i=1;i<=m;i++) link(es,i,inf,0); for (int i=1;i<=m;i++) for (int x,j=1;j<=n;j++) { scanf("%d",&x); if (x) link(n+m+i,j+m,inf,0); } for (int i=1;i<=m;i++) { scanf("%d",&s[i]); for (int j=1;j<=s[i];j++) scanf("%d",&T[i][j]); for (int j=1;j<=s[i]+1;j++) scanf("%d",&w[i][j]); for (int j=1;j<=s[i];j++) link(i,n+m+i,T[i][j]-T[i][j-1],w[i][j]); link(i,n+m+i,inf,w[i][s[i]+1]); } printf("%lld",EK()); return 0; }
This passage is made by MashiroSky.