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


Problem Description
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. 
 
Input
The input contains multiple test cases.
Each case first line given the integer n (2<n<30) 
Than n lines,each line include n positive integers.(<100)
 
Output
For each test case output the maximal values yifenfei can get.
 
Sample Input
2
10 3
5 10
3
10 3 3
2 5 3
6 7 10
5
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
 
Sample Output
28
46
80
 
Author
yifenfei
 
Source
 
Recommend
yifenfei   |   We have carefully selected several similar problems for you:  3376 1533 3416 3081 2448 
 

最大费用最大流,搞了好久= =!

题意:

    给出一个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
",ans);
33     }
34     return 0;
35 }
View Code

    先拆点构图,每个点一分为二,保证了只经过一次,其实网络流的方法就已经解决了这个问题,其次构图时注意把数变为负数,求最小费用最大流。

其实构好图后就是直接套模板了,所以构图的时候注意点,处理一下(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
",-cost_min_flow(s,e));
100     }
101     return 0;
102 }
原文地址:https://www.cnblogs.com/GO-NO-1/p/3726322.html