标签:
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 }
有另一种动态规划解法,网上称之为多线程dp。
end
标签:
原文地址:http://www.cnblogs.com/cs1131/p/5795588.html