hdu 2686 Matrix && hdu 3367 Matrix Again (最大费用最大流)
Matrix
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1394 Accepted Submission(s): 758
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.
Each case first line given the integer n (2<n<30)
Than n lines,each line include n positive integers.(<100)
最大费用最大流,搞了好久= =!
题意:
给出一个n*n的矩阵,求(1,1)到(n,n)的两条不想交不重叠的路径,使经过的点的和最大。
开始想到的是DP,后来发现了可以用多线程DP实现:
参考:http://www.cnblogs.com/jackge/archive/2013/04/17/3025628.html
让两个进程同时进行,枚举步数K,当x1==x2||y1==y2时跳过,得状态转移方程:
dp(k, x1, y1, x2, y2) = max(dp(k-1, x1-1, y1, x2-1, y2), dp(k-1, x1-1, y1, x2, y2-1), dp(k-1, x1, y1-1, x2-1, y2), dp(k-1, x1, y1-1,x2, y2-1))
+ data(x1, y1) + data(x2, y2) ;
由于只能走右或下,所以坐标满足x+y=k。这样就能降低维数为3维,方程:
dp(k, x1, x2) = max(dp(k-1, x1, x2), dp(k-1, x1-1, x2), dp(k-1, x1, x2-1), dp(k-1, x1-1, x2-1)) + data(x1, k-x1) + data(x2, k-x2) ;
code:
1 //31MS 1196K 880 B G++ 2 #include<stdio.h> 3 #include<string.h> 4 #define N 50 5 int p[N][N]; 6 int dp[2*N][N][N]; 7 int max(int a,int b) 8 { 9 return a>b?a:b; 10 } 11 int Max(int a,int b,int c,int d) 12 { 13 return max(a,max(b,max(c,d))); 14 } 15 int main(void) 16 { 17 int n; 18 while(scanf("%d",&n)!=EOF) 19 { 20 memset(dp,0,sizeof(dp)); 21 for(int i=0;i<n;i++) 22 for(int j=0;j<n;j++) 23 scanf("%d",&p[i][j]); 24 for(int k=1;k<2*n-2;k++) 25 for(int i=0;i<n;i++) 26 for(int j=0;j<n;j++){ 27 if(i==j) continue; 28 dp[k][i][j]=Max(dp[k-1][i][j],dp[k-1][i-1][j],dp[k-1][i][j-1],dp[k-1][i-1][j-1]); 29 dp[k][i][j]+=p[i][k-i]+p[j][k-j]; 30 } 31 int ans=max(dp[2*n-3][n-1][n-2],dp[2*n-3][n-2][n-1])+p[0][0]+p[n-1][n-1]; 32 printf("%d\n",ans); 33 } 34 return 0; 35 }
先拆点构图,每个点一分为二,保证了只经过一次,其实网络流的方法就已经解决了这个问题,其次构图时注意把数变为负数,求最小费用最大流。
其实构好图后就是直接套模板了,所以构图的时候注意点,处理一下(1,1)和(n,n)两个点,因为会经过两次。
code:
1 //31MS 384K 2396 B G++ 2 #include<stdio.h> 3 #include<string.h> 4 #include<queue> 5 #define N 2005 6 #define inf 0x7ffffff 7 using namespace std; 8 struct node{ 9 int u,v,c,w; 10 int next; 11 }edge[10*N]; 12 int vis[N]; 13 int Head[N],d[N],edgenum; 14 int pre[N],path[N]; 15 void addedge(int u,int v,int c,int w) 16 { 17 edge[edgenum].u=u; 18 edge[edgenum].v=v; 19 edge[edgenum].c=c; 20 edge[edgenum].w=w; 21 edge[edgenum].next=Head[u]; 22 Head[u]=edgenum++; 23 24 edge[edgenum].u=v; 25 edge[edgenum].v=u; 26 edge[edgenum].c=0; 27 edge[edgenum].w=-w; 28 edge[edgenum].next=Head[v]; 29 Head[v]=edgenum++; 30 } 31 int SPFA(int s,int e) 32 { 33 memset(vis,0,sizeof(vis)); 34 memset(pre,-1,sizeof(pre)); 35 for(int i=0;i<=e;i++) 36 d[i]=inf; 37 queue<int>Q; 38 d[s]=0; 39 vis[s]=1; 40 Q.push(s); 41 while(!Q.empty()){ 42 int u=Q.front(); 43 Q.pop(); 44 vis[u]=0; //这里WA了好多次 45 for(int i=Head[u];i!=-1;i=edge[i].next){ 46 int v=edge[i].v; 47 int w=edge[i].w; 48 if(edge[i].c>0 && d[v]>d[u]+w){ 49 pre[v]=u; 50 path[v]=i; 51 d[v]=d[u]+w; 52 if(!vis[v]){ 53 vis[v]=1; 54 Q.push(v); 55 } 56 } 57 } 58 } 59 if(pre[e]!=-1) return 1; 60 return 0; 61 } 62 int cost_min_flow(int s,int e) 63 { 64 int cost=0; 65 while(SPFA(s,e)){ 66 int minc=inf; 67 for(int i=e;i!=s;i=pre[i]){ 68 minc=minc<edge[path[i]].c?minc:edge[path[i]].c; 69 } 70 for(int i=e;i!=s;i=pre[i]){ 71 edge[path[i]].c-=minc; 72 edge[path[i]^1].c+=minc; 73 cost+=minc*edge[path[i]].w; 74 } 75 } 76 return cost; 77 } 78 int main(void) 79 { 80 int n; 81 int p[50][50]; 82 while(scanf("%d",&n)!=EOF) 83 { 84 edgenum=0; 85 memset(Head,-1,sizeof(Head)); 86 int k=n*n; 87 int s=0,e=2*k+1; 88 for(int i=1;i<=n;i++) 89 for(int j=1;j<=n;j++){ 90 scanf("%d",&p[i][j]); 91 addedge(j+(i-1)*n,k+j+(i-1)*n,1,-p[i][j]); 92 if(j!=n) addedge(k+j+(i-1)*n,j+1+(i-1)*n,1,0); 93 if(i!=n) addedge(k+j+(i-1)*n,j+i*n,1,0); 94 } 95 addedge(s,1,2,0); 96 addedge(1,k+1,1,0); 97 addedge(2*k,e,2,0); 98 addedge(k,2*k,1,0); 99 printf("%d\n",-cost_min_flow(s,e)); 100 } 101 return 0; 102 }