题意:给一个矩阵,每个格子有权值,从左上角,向下向右走到右下角,再从右下角向上向左走到左上角,每个格子只能走一次,问走完这一趟最小权值为多少?
想法:从左上角,向下向右走到右下角,再从右下角向上向左走到左上角,就相当于从左上角走到右下角,走两次,两次过程中,不能有点被走两次。这不就是费用流,找增广路的过程吗?先找一个当前费用最小的,然后接下来,这些点都无法走,然后再找费用最小的。
1.虚拟sink,source点
2.source到点(1,1)连一条容量为2,费用为0的边,这里你也可以容量设为inf,只要找费用流的时候,找两次,然后跳出就好了。
3.每一个点(x,y)向右下连边,容量为1费用为该点权值。
4.(n,n)向sink连一条容量为inf,费用为0的边。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define inf 0x7fffffff using namespace std; const int nodes=2000; const int edges=10000; struct node { int u,v,next; int flow,fee; }e[edges]; int head[nodes],cnt; int n,s,t; int map[50][50]; class Dinic { public: int spfa() { memset(vis,0,sizeof(vis)); memset(pe,-1,sizeof(pe)); for(int i=s;i<=t;i++) dis[i]=-inf; queue<int>q; while(!q.empty()) q.pop(); dis[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]<dis[u]+e[i].fee&&e[i].flow>0) { dis[v]=dis[u]+e[i].fee; pe[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[t]!=-inf; } int result() { int res=0; while(spfa()) { for(int i=pe[t];i+1;i=pe[e[i].u]) { e[i].flow-=1; e[i^1].flow+=1; } res+=dis[t]; } return res; } private: int dis[nodes],pe[nodes],vis[nodes]; }dinic; void Init() { memset(head,-1,sizeof(head)); cnt=0; } void add(int a,int b,int flow,int fee) { e[cnt].u=a; e[cnt].v=b; e[cnt].flow=flow; e[cnt].fee=fee; e[cnt].next=head[a]; head[a]=cnt++; e[cnt].u=b; e[cnt].v=a; e[cnt].flow=0; e[cnt].fee=-fee; e[cnt].next=head[b]; head[b]=cnt++; } int main() { while(~scanf("%d",&n)) { Init(); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&map[i][j]); } } s=0;t=2*n*n+1; add(s,1,2,0); add(n*n,t,2,0); for(int i=1;i<n;i++) { for(int j=1;j<n;j++) { int now=(i-1)*n+j; int you=now+1; int xia=now+n; if(now==1) { add(now,you,1,0); add(now,xia,1,0); continue; } add(n*n+now,you,1,0); add(n*n+now,xia,1,0); add(now,n*n+now,1,map[i][j]); } } for(int i=1;i<n;i++) { int now=(n-1)*n+i; add(n*n+now,now+1,1,0); add(now,n*n+now,1,map[n][i]); } for(int i=1;i<n;i++) { int now=(i-1)*n+n; add(n*n+now,now+n,1,0); add(now,n*n+now,1,map[i][n]); } int res=dinic.result(); printf("%d\n",res+map[1][1]+map[n][n]); } return 0; }
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define inf 0x7fffffff using namespace std; const int nodes=750000; const int edges=2500000; struct node { int u,v,next; int flow,fee; }e[edges]; int head[nodes],cnt; int n,s,t; int map[605][605]; class Dinic { public: int spfa() { memset(vis,0,sizeof(vis)); memset(pe,-1,sizeof(pe)); for(int i=s;i<=t;i++) dis[i]=-inf; queue<int>q; while(!q.empty()) q.pop(); dis[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]<dis[u]+e[i].fee&&e[i].flow>0) { dis[v]=dis[u]+e[i].fee; pe[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[t]!=-inf; } int result() { int res=0; while(spfa()) { for(int i=pe[t];i+1;i=pe[e[i].u]) { e[i].flow-=1; e[i^1].flow+=1; } res+=dis[t]; } return res; } private: int dis[nodes],pe[nodes],vis[nodes]; }dinic; void Init() { memset(head,-1,sizeof(head)); cnt=0; } void add(int a,int b,int flow,int fee) { e[cnt].u=a; e[cnt].v=b; e[cnt].flow=flow; e[cnt].fee=fee; e[cnt].next=head[a]; head[a]=cnt++; e[cnt].u=b; e[cnt].v=a; e[cnt].flow=0; e[cnt].fee=-fee; e[cnt].next=head[b]; head[b]=cnt++; } int main() { while(~scanf("%d",&n)) { Init(); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&map[i][j]); } } s=0;t=2*n*n+1; add(s,1,2,0); add(n*n,t,2,0); for(int i=1;i<n;i++) { for(int j=1;j<n;j++) { int now=(i-1)*n+j; int you=now+1; int xia=now+n; if(now==1) { add(now,you,1,0); add(now,xia,1,0); continue; } add(n*n+now,you,1,0); add(n*n+now,xia,1,0); add(now,n*n+now,1,map[i][j]); } } for(int i=1;i<n;i++) { int now=(n-1)*n+i; add(n*n+now,now+1,1,0); add(now,n*n+now,1,map[n][i]); } for(int i=1;i<n;i++) { int now=(i-1)*n+n; add(n*n+now,now+n,1,0); add(now,n*n+now,1,map[i][n]); } int res=dinic.result(); printf("%d\n",res+map[1][1]+map[n][n]); } return 0; }