HDU 2686

http://acm.split.hdu.edu.cn/showproblem.php?pid=2686

 

and

 

http://codevs.cn/problem/1169/

 

题意: 从矩阵左上角1,1,走到右下角n,n,每次只能向右或向下走,到达nn后,再走回1,1,往回走时,每次只能向左或者向上走,除了11和nn,其他点在去和回的路径中只能出现一次,问权值和最大的来回的路径是多少。

解法:找一条来回的路径,相当于从11到nn找两条点不重复的路径,使得两条的和最大。 相当于从源点 给11一个2的流量, nn给汇点一个n的流量, 跑最大流, 两个流经过的两条路就是要找的答案。 为了保证一个点只会被选择一次,考虑拆点。

把矩阵中的点xy,拆成两个点,一个称为in,一个称为out,所有指向这个点的边 连到in,所有从xy出发的边,从out点连出去, in-》out连流量为1,费用为- a【x】【y】,求最小费用最大流, 相反数就是最大权值和。其他的边就是往右和往下建边。

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int inf=0x3f3f3f3f;
  4 const int M=1e2+10;
  5 class MaxFlowMinCost { ///最小费用最大流O(~=V^3)
  6     typedef int typef;///流量的类型
  7     typedef int typec;///费用的类型
  8     static const int ME=1e6+10;///边的个数
  9     static const int MV=5e3+10;///点的个数
 10     queue<int> q;
 11     int n,cur[MV],pre[MV];
 12     bool used[MV],sign[MV];
 13     typef flow;
 14     typec cost,dist[MV];
 15     bool spfa(int s,int t) {
 16         for(int i=0; i<=n; i++) {
 17             used[i]=sign[i]=dist[i]=0;
 18         }
 19         used[s]=sign[s]=true;
 20         while(!q.empty()) q.pop();
 21         q.push(s);
 22         while(!q.empty()) {
 23 //            - 24 -
 24             int u=q.front();
 25             q.pop();
 26             used[u]=false;
 27             for(int i=g.head[u]; ~i; i=g.e[i].next) {
 28                 if(g.e[i].flow<1) continue;
 29                 int v=g.e[i].v;
 30                 typec c=g.e[i].cost;
 31                 if(!sign[v]||dist[v]>dist[u]+c) {
 32                     dist[v]=dist[u]+c;
 33                     sign[v]=true;
 34                     pre[v]=u;
 35                     cur[v]=i;
 36                     if(used[v]) continue;
 37                     used[v]=true;
 38                     q.push(v);
 39                 }
 40             }
 41         }
 42         return sign[t];
 43     }
 44     struct G {
 45         struct E {
 46             int v,next;
 47             typef flow;
 48             typec cost;
 49         } e[ME];
 50         int le,head[MV];
 51         void init(int n) {
 52             le=0;
 53             for(int i=0; i<=n; i++) head[i]=-1;
 54         }
 55         void add(int u,int v,typef flow,typec cost) {
 56             e[le].v=v;
 57             e[le].flow=flow;
 58             e[le].cost=cost;
 59             e[le].next=head[u];
 60             head[u]=le++;
 61         }
 62     } g;
 63 public:
 64     void init(int tn) {
 65         n=tn;
 66         g.init(n);
 67     }
 68 //    - 25 -
 69     void add(int u,int v,typef flow,typec cost) {
 70         g.add(u,v,flow,cost);
 71         g.add(v,u,0,-cost);
 72     }
 73     void solve(int s,int t) {
 74         flow=cost=0;
 75         while(spfa(s,t)) {
 76             int temp=t;
 77             typef now=inf;
 78             while(temp!=s) {
 79                 now=min(now,g.e[cur[temp]].flow);
 80                 temp=pre[temp];
 81             }
 82             flow+=now;
 83             temp=t;
 84             while(temp!=s) {
 85                 int id=cur[temp];
 86                 cost+=now*g.e[id].cost;
 87                 g.e[id].flow-=now;
 88                 g.e[id^1].flow+=now;
 89                 temp=pre[temp];
 90             }
 91         }
 92     }
 93     typef getflow() {
 94         return flow;
 95     }
 96     typec getcost() {
 97         return cost;
 98     }
 99 } gx;
100 int a[M][M];
101 int in[M][M];
102 int out[M][M];
103 int n,m;
104 int solve() {
105     int id=0;
106     for(int i=0; i<n; i++) {
107         for(int j=0; j<m; j++) {
108             in[i][j]=id;
109             id++;
110         }
111     }
112     for(int i=0; i<n; i++) {
113         for(int j=0; j<m; j++) {
114             out[i][j]=id;
115             id++;
116         }
117     }
118     int s=id;
119     id++;
120     int t=id;
121     id++;
122     gx.init(t);
123     gx.add(s,in[0][0],2,0);
124     gx.add(out[n-1][m-1],t,2,0);
125     for(int i=0; i<n; i++) {
126         for(int j=0; j<m; j++) {
127             int flow=1;
128             if(i==0&&j==0) flow=2;
129             if(i==n-1&&j==m-1) flow=2;
130             gx.add(in[i][j],out[i][j],flow,-a[i][j]);
131             if(i+1<n) {
132                 gx.add(out[i][j],in[i+1][j],1,0);
133             }
134             if(j+1<m) {
135                 gx.add(out[i][j],in[i][j+1],1,0);
136             }
137         }
138     }
139     gx.solve(s,t);
140     return -gx.getcost();
141 }
142 int main() {
143     while(~scanf("%d",&n)) {
144         m=n;
145         for(int i=0; i<n; i++) {
146             for(int j=0; j<m; j++) {
147                 scanf("%d",&a[i][j]);
148             }
149         }
150         printf("%d\n",solve()-a[0][0]-a[n-1][n-1]);
151     }
152     return 0;
153 }
View Code

 

有另一种动态规划解法,网上称之为多线程dp。 

 

思想是,每一步让两条路同时向前走一格,状态dp【】【】【】【】记录了第一条路径终点在x1y1,第二条路径终点在x2y2这个状态的最大值,然后当两条路径走到同一个点,且这个点不是nm时,这种情况是不允许的,即可。因为两个路是同时走的,所以相撞的点只可能是终点,因为从11到某一个点xy需要的步数是定值(x-1)+(y-1)。转移有4个,因为每条路都有右下两种选法,两条路,所以有四种情况。

 

 1 #include<bits/stdc++.h>
 2 #define mt(a,b) memset(a,b,sizeof(a))
 3 using namespace std;
 4 const int inf=0x3f3f3f3f;
 5 const int M=32;
 6 int n,m;
 7 int a[M][M];
 8 int dp[M][M][M][M];
 9 int dfs(int x1,int y1,int x2,int y2){
10     int &d=dp[x1][y1][x2][y2];
11     if(~d) return d;
12     if(x1==x2&&y1==y2&&(x1!=n-1||y1!=m-1)&&(x1!=0||y1!=0)){
13         d=-inf;
14         return d;
15     }
16     d=0;
17     if(x1>0&&x2>0){
18         d=max(d,dfs(x1-1,y1,x2-1,y2));
19     }
20     if(x1>0&&y2>0){
21         d=max(d,dfs(x1-1,y1,x2,y2-1));
22     }
23     if(y1>0&&x2>0){
24         d=max(d,dfs(x1,y1-1,x2-1,y2));
25     }
26     if(y1>0&&y2>0){
27         d=max(d,dfs(x1,y1-1,x2,y2-1));
28     }
29     d+=a[x1][y1]+a[x2][y2];
30     return d;
31 }
32 int solve(){
33     mt(dp,-1);
34     return dfs(n-1,m-1,n-1,m-1);
35 }
36 int main() {
37     while(~scanf("%d",&n)) {
38         m=n;
39         for(int i=0; i<n; i++) {
40             for(int j=0; j<m; j++) {
41                 scanf("%d",&a[i][j]);
42             }
43         }
44         printf("%d\n",solve()-a[0][0]-a[n-1][m-1]);
45     }
46     return 0;
47 }
View Code

 

 

 

 

 

end 

posted @ 2016-08-22 14:49  cs1131  阅读(193)  评论(0编辑  收藏  举报