BZOJ 2879: [Noi2012]美食节
同上道题的建模方法,不过这道题的数据较大,要用动态加边,判断每位厨师的最后一个点是否已用,如果用过,才添加下一个点
CODE:
# include <cstdio> # include <iostream> # include <cstring> # include <algorithm> # include <queue> #define maxn 1000 #define maxm 180000 #define inf 0x7fffffff using 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 ; } |