BZOJ 2879: [Noi2012]美食节
同上道题的建模方法,不过这道题的数据较大,要用动态加边,判断每位厨师的最后一个点是否已用,如果用过,才添加下一个点
CODE:
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<queue>#define maxn 1000#define maxm 180000#define inf 0x7fffffffusing namespace std;struct edges{ int to,cap,dist,next;}edge[maxm];int s,t,next[maxn],l;int addedge(int from,int to,int cap,int dist){ l++; edge[l*2]=(edges){to,cap,dist,next[from]}; edge[l*2+1]=(edges){from,0,-dist,next[to]}; next[from]=l*2;next[to]=l*2+1; return 0;}bool b[maxn];int dist[maxn],node,way[maxn];queue<int> q;bool spfa(){ for (int i=1;i<=node;i++) dist[i]=inf; memset(b,0,sizeof(b)); dist[s]=0; q.push(s); while (!q.empty()){ int u=q.front();q.pop(); b[u]=0; for (int i=next[u];i;i=edge[i].next) if (edge[i].cap&&dist[u]+edge[i].dist<dist[edge[i].to]) { dist[edge[i].to]=dist[u]+edge[i].dist; way[edge[i].to]=i; if (!b[edge[i].to]){ b[edge[i].to]=1;q.push(edge[i].to); } } } if (dist[t]==inf) return 0; return 1;}int n,m,ti[50][110],last[110],cnt[110];int mcmf(){ int cost=0; while (spfa()){ cost+=dist[t]; int x=t; while (x!=s){ edge[way[x]].cap-=1; edge[way[x]^1].cap+=1; x=edge[way[x]^1].to; } for (int i=1;i<=m;i++) if (!edge[last[i]].cap) { addedge(s,++node,1,0); last[i]=l*2;cnt[i]++; for (int j=1;j<=n;j++) addedge(node,2+j,1,cnt[i]*ti[j][i]); } } return cost;}int main(){ scanf("%d%d",&n,&m); s=1;t=2;node=n+2+m; for (int i=1;i<=n;i++) { int x; scanf("%d",&x); addedge(i+2,t,x,0); } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&ti[i][j]); for (int i=1;i<=m;i++) { cnt[i]=1; addedge(s,i+2+n,1,0); last[i]=l*2; for (int j=1;j<=n;j++) addedge(i+2+n,2+j,1,cnt[i]*ti[j][i]); } printf("%d\n",mcmf()); return 0;} |
浙公网安备 33010602011771号