对于每个点拆点成为两个点a,b,连接a到b的上界为1,下界为1的边,保证用过一次且仅一次。
然后若点u可到达点v,则连接即可。建成了一个上下界网络,将下界拆出去,求最大费用最大流就好。
#include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=800; const int MAXE=200000; const int inf=1<<30; int head[N],s,t,cnt,ans,ss,tt; int d[N],pre[N]; bool vis[N]; int q[MAXE]; struct Edge { int u,v,c,w,next; }edge[MAXE]; void addedge(int u,int v,int w,int c) { edge[cnt].u=u; edge[cnt].v=v; edge[cnt].w=w; edge[cnt].c=c; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].u=v; edge[cnt].w=-w; edge[cnt].c=0; edge[cnt].next=head[v]; head[v]=cnt++; } int SPFA() { int l,r; memset(pre,-1,sizeof(pre)); memset(vis,0,sizeof(vis)); for(int i=0;i<=t;i++) d[i]=inf; d[s]=0; l=0;r=0; q[r++]=s; vis[s]=1; while(l<r) { int u=q[l++]; vis[u]=0; for(int j=head[u];j!=-1;j=edge[j].next) { int v=edge[j].v; if(edge[j].c>0&&d[u]+edge[j].w<d[v]) { d[v]=d[u]+edge[j].w; pre[v]=j; if(!vis[v]) { vis[v]=1; q[r++]=v; } } } } if(d[t]==inf) return 0; return 1; } int MCMF() { int flow=0; while(SPFA()) { int u=t; int mini=inf; while(u!=s) { if(edge[pre[u]].c<mini) mini=edge[pre[u]].c; u=edge[pre[u]].u; } flow+=mini; u=t; ans+=d[t]*mini; while(u!=s) { edge[pre[u]].c-=mini; edge[pre[u]^1].c+=mini; u=edge[pre[u]].u; } } return flow; } int main() { int cas,n,m,k; scanf("%d",&cas); int val[20][20],id[20][20]; int now=0; char str[20]; while(cas--) { now++; int i,j,l; scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;i++) { scanf("%s",str+1); for(j=1;j<=m;j++) val[i][j]=str[j]-‘0‘; } s=0;ss=m*n*2+1; t=m*n*2+4;tt=m*n*2+3; for(i=0;i<=t;i++) head[i]=-1; cnt=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) id[i][j]=++cnt; cnt=0; addedge(tt,ss,0,inf); addedge(ss,ss+1,0,k); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { addedge(s,id[i][j],0,1); addedge(id[i][j]+m*n,t,0,1); addedge(id[i][j],tt,0,1); addedge(ss+1,id[i][j]+m*n,0,1); for(l=j+1;l<=m;l++) { if(val[i][j]==val[i][l]) addedge(id[i][j],id[i][l]+m*n,l-j-1-val[i][j],1); else addedge(id[i][j],id[i][l]+m*n,l-j-1,1); } for(l=i+1;l<=n;l++) { if(val[l][j]==val[i][j]) addedge(id[i][j],id[l][j]+m*n,l-i-1-val[i][j],1); else addedge(id[i][j],id[l][j]+m*n,l-i-1,1); } } ans=0; int flow=MCMF(); if(flow==m*n) printf("Case %d : %d\n",now,-ans); else printf("Case %d : -1\n",now); } return 0; }
hdu 4862 Jump 上下界费用流,布布扣,bubuko.com
原文:http://www.cnblogs.com/vermouth/p/3911113.html