「BZOJ2879」[Noi2012]美食节
这道题就是 「BZOJ1070」[SCOI2007]修车 的加强版
如果一开始把全部边连上会T
优化的方法是只连用到过和下一次增广可能用到的边。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=50,M=110,NN=100010,oo=1e9; 4 int n,m,cost[N][M],tot,s,t,p[N],rank[NN],c[NN]; 5 bool isend[NN]; 6 struct Edge{ 7 int from,to,flow,cap,w; 8 }; 9 int edge_tot; 10 vector<Edge>edge; 11 vector<int>point[NN]; 12 void add_edge(int f,int t,int cc,int ww){ 13 edge.push_back((Edge){f,t,0,cc,ww}); 14 point[f].push_back(edge_tot++); 15 edge.push_back((Edge){t,f,0,0,-ww}); 16 point[t].push_back(edge_tot++); 17 return; 18 } 19 int dis[NN],pre[NN]; 20 bool inq[NN]; 21 bool spfa(){ 22 queue<int>q; 23 int x; 24 for(int i=1;i<=tot;i++) dis[i]=oo; 25 q.push(s); 26 dis[s]=0,inq[s]=1; 27 while(!q.empty()){ 28 x=q.front();q.pop(); 29 inq[x]=0; 30 for(int i=0;i<point[x].size();i++){ 31 Edge& e=edge[point[x][i]]; 32 if(e.cap<=e.flow) continue; 33 if(dis[x]+e.w<dis[e.to]){ 34 dis[e.to]=dis[x]+e.w,pre[e.to]=point[x][i]; 35 if(!inq[e.to]){inq[e.to]=1;q.push(e.to);} 36 } 37 } 38 } 39 return dis[t]<oo; 40 } 41 int mincostmaxflow(){ 42 int ans=0,f,now; 43 while(spfa()){ 44 f=oo,now=t; 45 while(now!=s){ 46 f=min(f,edge[pre[now]].cap-edge[pre[now]].flow); 47 if(isend[now]){ 48 isend[now]=0,isend[++tot]=1,rank[tot]=rank[now]+1,c[tot]=c[now]; 49 add_edge(tot,t,1,0); 50 for(int i=3;i<=n+2;i++) add_edge(i,tot,1,rank[tot]*cost[i-2][c[tot]]); 51 } 52 now=edge[pre[now]].from; 53 } 54 ans+=dis[t]*f,now=t; 55 while(now!=s){ 56 edge[pre[now]].flow+=f,edge[pre[now]^1].flow-=f; 57 now=edge[pre[now]].from; 58 } 59 } 60 return ans; 61 } 62 int main(){ 63 scanf("%d%d",&n,&m); 64 for(int i=1;i<=n;i++) scanf("%d",&p[i]); 65 for(int i=1;i<=n;i++) 66 for(int j=1;j<=m;j++)scanf("%d",&cost[i][j]); 67 s=++tot,t=++tot; 68 for(int i=1;i<=n;i++) add_edge(s,++tot,p[i],0); 69 for(int i=1;i<=m;i++){ 70 add_edge(++tot,t,1,0); 71 rank[tot]=1,c[tot]=i,isend[tot]=1; 72 for(int j=3;j<=n+2;j++) add_edge(j,i+n+2,1,cost[j-2][i]); 73 } 74 int ans=mincostmaxflow(); 75 printf("%d",ans); 76 }