【CODEVS】1033 蚯蚓的游戏问题
【算法】网络流-最小费用最大流(费用流)
【题解】与方格取数2类似
在S后添加辅助点S_,限流k
每条边不能重复走,限流1
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int inf=0x3f3f3f3f,maxn=40,maxN=5000; struct edge{int from,v,flow,cost;}e[150000]; int n,m,k,tot=1,first[maxN],p[maxn][maxn*2],q[1010],d[maxN],N,S,T,S_;//梯形输入,p的第二维翻倍 long long ans; bool vis[maxN]; void insert(int u,int v,int flow,int cost) { tot++;e[tot].v=v;e[tot].flow=flow;e[tot].cost=cost;e[tot].from=first[u];first[u]=tot; tot++;e[tot].v=u;e[tot].flow=0;e[tot].cost=-cost;e[tot].from=first[v];first[v]=tot; } bool spfa() { memset(d,0x3f,(N+N+3)*4); memset(vis,0,N+N+3); int head=0,tail=1;q[0]=T; vis[T]=1;d[T]=0; while(head!=tail) { int x=q[head++];if(head>=1001)head=0; for(int i=first[x];i;i=e[i].from) if(e[i^1].flow&&e[i^1].cost+d[x]<d[e[i].v]) { d[e[i].v]=d[x]+e[i^1].cost; if(!vis[e[i].v]) { vis[e[i].v]=1;q[tail++]=e[i].v; if(tail>=1001)tail=0; } } vis[x]=0; } return d[S]<inf; } int dfs(int x,int a) { vis[x]=1; if(x==T||a==0)return a; int flow=0,f; for(int i=first[x];i;i=e[i].from) if(!vis[e[i].v]&&d[e[i].v]+e[i].cost==d[x]&&(f=dfs(e[i].v,min(a,e[i].flow)))>0)//记得判vis { e[i].flow-=f;//正边-,反向弧+ e[i^1].flow+=f; ans+=e[i].cost*f; a-=f; flow+=f; if(a==0)break; } return flow; } int main() { scanf("%d%d%d",&n,&m,&k); N=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m+i-1;j++) { N++; p[i][j]=N; } } S=0,S_=N+N+1,T=N+N+2;//N计算出来后才赋值 for(int i=1;i<=n;i++) { for(int j=1;j<=m+i-1;j++) { int x; scanf("%d",&x); insert(p[i][j],p[i][j]+N,1,-x); if(i<n) { insert(p[i][j]+N,p[i+1][j],1,0); insert(p[i][j]+N,p[i+1][j+1],1,0); } } } insert(S,S_,k,0); for(int i=1;i<=m;i++)insert(S_,i,1,0); for(int i=1;i<=m+n-1;i++)insert(p[n][i]+N,T,1,0); ans=0; while(spfa()) { // for(int i=0;i<=N+N+2;i++)printf("[%d]%d\n",i,d[i]); memset(vis,0,N+N+3); dfs(S,inf); } printf("%lld",-ans); return 0; }