题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686
Yifenfei very like play a number game in the n*n Matrix. A positive integer number is put in each area of the Matrix.
Every time yifenfei should to do is that choose a detour which frome the top left point to the bottom right point and than back to the top left point with the maximal values of sum integers that area of Matrix yifenfei choose. But from the top to the bottom can only choose right and down, from the bottom to the top can only choose left and up. And yifenfei can not pass the same area of the Matrix except the start and end.
Every time yifenfei should to do is that choose a detour which frome the top left point to the bottom right point and than back to the top left point with the maximal values of sum integers that area of Matrix yifenfei choose. But from the top to the bottom can only choose right and down, from the bottom to the top can only choose left and up. And yifenfei can not pass the same area of the Matrix except the start and end.
题意描述:n*n的矩阵,每个数为正整数,要求从最左上的位置走到最右下的位置,每次只能向右或向下走一格,然后又从最右下的位置回到最左上的位置,每次只能向上或向左走一格,然后累加这两次路径上的数。注意每个格子只能走一次(除去最左上和最右下),即矩阵中的每个数只能加一次。
算法分析:这道题可以运用DP来做,但我的DP思维有限,还不大熟悉,刚好最近刷图论题,介绍一下用最小费用最大流算法解之。
把最左上看作源点,最右下看作汇点。从上往下走一次,再从下往上走一次,其实就等同于从上往下走两次罢了,即从源点到汇点找到两条价值最大且不相交的路径。
首先拆点建图:(i-1)*n+j->(i-1)*n+j+n*n(w为1(注意:源点和汇点为2,因为要找到两条路),cost为矩阵中这个数值);
(i-1)*n+j+n*n -> (i-1)*n+j+1(w为1,cost为0)
(i-1)*n+j+n*n -> i*n+j(w为1,cost为0)
然后用费用流求解即可。(不是题中明确说明每个数都为正吗,我dis[]函数初始化0WA了,这是为什么?)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 0x7fffffff 10 using namespace std; 11 const int maxn=20000+10; 12 const int M = 9999999; 13 14 int n,from,to; 15 struct node 16 { 17 int v,flow,cost; 18 int next; 19 }edge[M*3]; 20 int head[maxn],edgenum; 21 int dis[maxn],pre[maxn],pid[maxn],vis[maxn]; 22 int an[33][33]; 23 24 void add(int u,int v,int flow,int cost) 25 { 26 edge[edgenum].v=v ;edge[edgenum].flow=flow; 27 edge[edgenum].cost=cost ;edge[edgenum].next=head[u]; 28 head[u]=edgenum++; 29 30 edge[edgenum].v=u ;edge[edgenum].flow=0; 31 edge[edgenum].cost=-cost ;edge[edgenum].next=head[v]; 32 head[v]=edgenum++; 33 } 34 35 int spfa() 36 { 37 memset(vis,0,sizeof(vis)); 38 memset(dis,-1,sizeof(dis)); 39 queue<int> Q; 40 Q.push(from); 41 dis[from]=0; 42 vis[from]=1; 43 while (!Q.empty()) 44 { 45 int u=Q.front() ;Q.pop(); 46 vis[u]=0; 47 for (int i=head[u] ;i!=-1 ;i=edge[i].next) 48 { 49 int v=edge[i].v; 50 if (edge[i].flow>0 && dis[v]<dis[u]+edge[i].cost) 51 { 52 dis[v]=dis[u]+edge[i].cost; 53 pre[v]=u; 54 pid[v]=i; 55 if (!vis[v]) 56 { 57 vis[v]=1; 58 Q.push(v); 59 } 60 } 61 } 62 } 63 return dis[to]; 64 } 65 66 int mincost() 67 { 68 int aug=0,maxflow=0; 69 int ans=0; 70 int ncase=0; 71 while (1) 72 { 73 aug=inf; 74 int tmp=spfa(); 75 if (tmp==0) break; 76 for (int i=to ;i!=from ;i=pre[i]) 77 { 78 if (edge[pid[i] ].flow<aug) 79 aug=edge[pid[i] ].flow; 80 } 81 for (int i=to ;i!=from ;i=pre[i]) 82 { 83 edge[pid[i] ].flow -= aug; 84 edge[pid[i]^1 ].flow += aug; 85 } 86 ans += tmp; 87 ncase++; 88 if (ncase==2) break; 89 } 90 return ans-an[1][1]-an[n][n]; 91 } 92 93 int main() 94 { 95 while (scanf("%d",&n)!=EOF) 96 { 97 memset(head,-1,sizeof(head)); 98 edgenum=0; 99 for (int i=1 ;i<=n ;i++) 100 { 101 for (int j=1 ;j<=n ;j++) 102 scanf("%d",&an[i][j]); 103 } 104 from=1; 105 to=2*n*n; 106 for (int i=1 ;i<=n ;i++) 107 { 108 for (int j=1 ;j<=n ;j++) 109 { 110 int u=(i-1)*n+j; 111 int v=(i-1)*n+j+n*n; 112 add(u,v,1,an[i][j]); 113 if (j+1<=n) add(v,u+1,1,0); 114 if (i+1<=n) add(v,i*n+j,1,0); 115 } 116 } 117 add(from,from+n*n,1,an[1][1]); 118 add(n*n,to,1,an[n][n]); 119 int sum=mincost(); 120 printf("%d\n",sum); 121 } 122 return 0; 123 }