USACO 5.4 Canada Tour (DP / 最大费用最大流)

2015-04-01 20:25:02

思路:好题!

  题意可以转化为:两个人从起点到终点(两人的路径不能有交点),仅能从左向右走,求最多能经过多少点。

  方法1:DP:

    想了很久... 基本可以想到用dp[i][j]来表示一人走到 i ,另一人走到 j 能经过的最多点数。但是转移方程怎么想都难以避免重复...

    看了别人的博客,发现一个很巧妙的方法。

    首先发现,dp[i][j] = dp[j][i](两个人可以换位置),dp[i][j] = max{dp[i][k]} (1<=k<j , k与j有边相连)

    关于如何避免重复,我思考良久... 结果还是不太清晰。在转移方程时保证:j > i ,这样如果dp[i][k]的路径没有重复点,dp[i][j]的路径也不可能有重复点。

    (这种转移方法每次只走一个人,而且走的是走完之后更右边的那个人。j > i)

  方法2:网络流:

    并没有想到这种做法... 百度了才知道还能用网络流做。

    将每个点拆点(i 拆成 ia , ib),ia -> ib 建立容量为1,费用为1的边。为了实现两个走的条件,给起点1a->1b的边容量设为2,终点na->nb的边容量设为2。

    然后根据题目的输入给点之间建立边,要注意建边条件:从左到右(当时这里坑了...)

    最后跑一遍最大费用最大流,如果流量<2,那么答案就为1。否则输出费用即可。

 

DP:

 1 /*
 2 ID:naturec1
 3 PROG: tour
 4 LANG: C++
 5 */
 6 #include <cstdio>
 7 #include <cstring>
 8 #include <cstdlib>
 9 #include <cmath>
10 #include <vector>
11 #include <map>
12 #include <set>
13 #include <stack>
14 #include <queue>
15 #include <string>
16 #include <iostream>
17 #include <algorithm>
18 using namespace std;
19 
20 #define MEM(a,b) memset(a,b,sizeof(a))
21 #define REP(i,n) for(int i=0;i<(n);++i)
22 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
23 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
24 #define MP(a,b) make_pair(a,b)
25 
26 typedef long long ll;
27 typedef pair<int,int> pii;
28 const int INF = (1 << 30) - 1;
29 const int MAXN = 110;
30 
31 int N,M,ans;
32 bool g[MAXN][MAXN];
33 int dp[MAXN][MAXN];
34 map<string,int> mp;
35 
36 int main(){
37     freopen("tour.in","r",stdin);
38     freopen("tour.out","w",stdout);
39     string str1,str2;
40     scanf("%d%d",&N,&M);
41     REP(i,N){
42         cin >> str1;
43         mp[str1] = i + 1;
44     }
45     REP(i,M){
46         cin >> str1 >> str2;
47         int id1 = mp[str1];
48         int id2 = mp[str2];
49         g[id1][id2] = g[id2][id1] = true;
50     }
51     dp[1][1] = 1;
52     for(int i = 1; i <= N; ++i){
53         for(int j = i + 1; j <= N; ++j){
54             dp[i][j] = -INF;
55             for(int k = 1; k < j; ++k) if(g[k][j] && dp[i][k] > 0){
56                 dp[i][j] = max(dp[i][j],dp[i][k] + 1);
57             }
58             dp[j][i] = dp[i][j];
59         }
60     }
61     int ans = 1;
62     for(int i = 1; i <= N; ++i) if(g[i][N]){
63         ans = max(ans,dp[i][N]);
64     }
65     printf("%d\n",ans);
66     return 0;
67 }
View Code

 

最大费用最大流:

  1 /*
  2 ID:naturec1
  3 PROG: tour
  4 LANG: C++
  5 */
  6 #include <cstdio>
  7 #include <cstring>
  8 #include <cstdlib>
  9 #include <cmath>
 10 #include <vector>
 11 #include <map>
 12 #include <set>
 13 #include <stack>
 14 #include <queue>
 15 #include <string>
 16 #include <iostream>
 17 #include <algorithm>
 18 using namespace std;
 19 
 20 #define MEM(a,b) memset(a,b,sizeof(a))
 21 #define REP(i,n) for(int i=0;i<(n);++i)
 22 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
 23 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 24 #define MP(a,b) make_pair(a,b)
 25 
 26 typedef long long ll;
 27 typedef pair<int,int> pii;
 28 const int INF = (1 << 30) - 1;
 29 const int MAXN = 210;
 30 
 31 int N,M,st,ed;
 32 map<string,int> mp;
 33 int first[MAXN],ecnt;
 34 int dis[MAXN],prev[MAXN],pree[MAXN];
 35 int inq[MAXN];
 36 
 37 struct edge{
 38     int v,next,cp,cost;
 39 }e[MAXN * MAXN * 8];
 40 
 41 void Init(){
 42     MEM(first,-1);
 43     ecnt = 0;
 44 }
 45 
 46 void Add_edge(int u,int v,int cp,int cost){
 47     e[ecnt].next = first[u];
 48     e[ecnt].v = v;
 49     e[ecnt].cp = cp;
 50     e[ecnt].cost = cost;
 51     first[u] = ecnt++;
 52 
 53     e[ecnt].next = first[v];
 54     e[ecnt].v = u;
 55     e[ecnt].cp = 0;
 56     e[ecnt].cost = -cost;
 57     first[v] = ecnt++;
 58 }
 59 
 60 bool Spfa(){
 61     fill(dis + st,dis + ed + 1,-INF);
 62     dis[st] = 0;
 63     MEM(prev,-1);
 64     MEM(inq,0);
 65     queue<int> Q;
 66     while(!Q.empty()) Q.pop();
 67     Q.push(st);
 68     while(!Q.empty()){
 69         int x = Q.front(); Q.pop();
 70         inq[x] = 0;
 71         for(int i = first[x]; ~i; i = e[i].next){
 72             if(e[i].cp <= 0) continue;
 73             int v = e[i].v;
 74             if(dis[v] < dis[x] + e[i].cost){
 75                 dis[v] = dis[x] + e[i].cost;
 76                 prev[v] = x;
 77                 pree[v] = i;
 78                 if(inq[v] == 0){
 79                     inq[v] = 1;
 80                     Q.push(v);
 81                 }
 82             }
 83         }
 84     }
 85     return prev[ed] != -1;
 86 }
 87 
 88 int MCMF(){
 89     int max_cost = 0,cnt = 0;
 90     while(Spfa()){
 91         for(int i = ed; i != st; i = prev[i]){
 92             int id = pree[i];
 93             e[id].cp--;
 94             e[id ^ 1].cp++;
 95         }
 96         max_cost += dis[N];
 97         cnt++;
 98     }
 99     if(cnt < 2) return -1;
100     return max_cost;
101 }
102 
103 int main(){
104     freopen("tour.in","r",stdin);
105     freopen("tour.out","w",stdout);
106     Init();
107     string s1,s2;
108     scanf("%d%d",&N,&M);
109     REP(i,N){
110         cin >> s1;
111         mp[s1] = i + 1;
112     }
113     st = 1;
114     ed = N + N;
115     Add_edge(1,1 + N,2,1);
116     FOR(i,2,N - 1) Add_edge(i,i + N,1,1);
117     Add_edge(N,N + N,2,1);
118     REP(i,M){
119         cin >> s1 >> s2;
120         int id1 = mp[s1];
121         int id2 = mp[s2];
122         if(id1 < id2) Add_edge(id1 + N,id2,1,0);
123         else Add_edge(id2 + N,id1,1,0);
124     }
125     int ans = MCMF();
126     if(ans < 0) ans = 1;
127     printf("%d\n",ans);
128     return 0;
129 }
View Code

 

posted @ 2015-04-01 21:11  Naturain  阅读(154)  评论(0编辑  收藏  举报