费用流,其实是求传输一个容量为k的流的最大费用。主要是建图。原点为0,和1连上一条容量为k,费用为0的边,中间每个点拆成两个1和2,连上一条边,容量为k,费用为c,再连一条容量为比k大,费用为0的边,这样是为了跑完费用之后能继续跑拆完后的点和。然后和其他边连上就可以了。n*n和汇点连上一条容量为k,费用为0的边。我就是每次跑了一个容量为1的流,求打脸,不知道对不对。
#include<iostream> #include<queue> #include<cstdio> #include<cstring> using namespace std; const int inf=0x3f3f3f3f; struct edge { int to,nxt,c,f; }e[30011]; int n,k,cur,ans,cnt=1; int dist[30011],used[30011],pree[30011],prev[30011],g[30011]; void link(int u,int v,int f,int c) { e[++cnt].nxt=g[u]; g[u]=cnt; e[cnt].f=f; e[cnt].to=v; e[cnt].c=c; } void ins(int u,int v,int f,int c) { link(u,v,f,c); link(v,u,0,-c); } int Min(int x,int y) { return x<y?x:y; } bool spfa() { queue<int>q; memset(dist,-1,sizeof(dist)); memset(used,0,sizeof(used)); dist[0]=0; q.push(0); while(!q.empty()) { int u=q.front(); q.pop(); used[u]=0; for(int i=g[u];i;i=e[i].nxt) { int v=e[i].to,w=e[i].c; if(e[i].f&&dist[v]<dist[u]+w) { dist[v]=dist[u]+w; prev[v]=u; pree[v]=i; if(!used[v]) { q.push(v); used[v]=1; } } } } return dist[10010]!=-1; } int MinCostFlow() { int u=10010,sum=inf; while(u) { e[pree[u]].f--; e[pree[u]^1].f++; u=prev[u]; } // cout<<dist[10010]<<endl; return dist[10010]; } void MinFlow() { while(spfa()) { cur+=MinCostFlow(); if(cur>ans) ans=cur; } printf("%d",ans); } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { int x; scanf("%d",&x); ins((i-1)*n+j,(i-1)*n+j+n*n,1,x); ins((i-1)*n+j,(i-1)*n+j+n*n,k,0); if(i!=n) { ins((i-1)*n+j+n*n,i*n+j,k,0); } if(j!=n) { ins((i-1)*n+j+n*n,(i-1)*n+j+1,k,0); } } } ins(0,1,k,0); ins(n*n*2,10010,k,0); MinFlow(); return 0; }