洛谷P2770 双路DP // 网络流

https://www.luogu.org/problemnew/show/P2770

第一眼看过去,觉得这不是一个经典的双路DP模型吗,将一条过去一条回来互不相交的路径看作是起点出发了两条路径一起走向终点,用DP[i][j]表示一条路到i一条路到j的状态下经过的最大的城市,只要保证枚举的城市单调递增,一个n3 的DP就可以直接递推出答案,比较麻烦的是输出路径,开始使用记忆路径的操作但是总是蜜汁WA,后来直接在dp的过程中记录当前状态的前驱就可以了。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double eps = 1e-9;
const int maxn = 1010;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
string name[maxn];
map<string,int>P;
int MAP[maxn][maxn];
int ans[2][maxn];
int cnt1,cnt2;
int dp[maxn][maxn];
PII pre[maxn][maxn];
void out(int l,int r){
    if(l == 1 && r == 1) return;
    out(pre[l][r].fi,pre[l][r].se);
    if(pre[l][r].fi == l) ans[0][++cnt1] = r;
    else ans[1][++cnt2] = l;
}
int main(){
    Sca2(N,M); Mem(MAP,0);
    for(int i = 1; i <= N ; i ++){
        cin >> name[i];
        P[name[i]] = i;
    }
    for(int i = 1; i <= M ; i ++){
        string a,b;
        cin >> a >> b;
        MAP[P[a]][P[b]] = MAP[P[b]][P[a]] = 1;
    }
    if(N == 1){
        puts("1");
        cout << name[1] << endl;
        return 0;
    } 
    Mem(dp,-0x3f);
    dp[1][1] = 1;
    for(int i = 2; i <= N; i ++){
        for(int j = 1; j < i; j ++){
            for(int k = 1; k < i ; k ++){
                if(MAP[j][i] && dp[j][k] + 1 > dp[i][k]){
                    dp[i][k] = dp[j][k] + 1;
                    pre[i][k] = mp(j,k);
                }
                if(MAP[k][i] && dp[j][k] + 1 > dp[j][i]){
                    dp[j][i] = dp[j][k] + 1;
                    pre[j][i] = mp(j,k);
                }
            }
        }
    }
    int Ans = -INF;
    for(int i = 1; i <= N - 1; i ++){
        if(MAP[N][i]) Ans = max(dp[i][N],Ans);
    }
    if(Ans <= 0){
        puts("No Solution!");
        return 0;
    }
    Pri(Ans);
    for(int i = N - 1; i >= 1; i --){
        if(MAP[N][i] && dp[i][N] == Ans){
            out(i,N);
            break;
        }
    }
    if(ans[1][1] != 1) cout << name[1] << endl;
    for(int i = 1; i <= cnt1; i ++) cout << name[ans[0][i]] << endl;
    for(int i = cnt2; i >= 1; i --) cout << name[ans[1][i]] << endl;
    if(ans[0][1] != 1) cout << name[1] << endl;
    return 0;
}
DP

做完了发现这是一道网络流专题里面的题目,想了想还真是。

相当于两条不同的水流同时流向终点,需要保证的是最大流的流量是2,其次除了起点每个点只能流通一次,解决的方法就是将每个点拆点成为i 和i + N,在他们之间建立一条容量为1的边,同时i为入点i + N为出点,保证每个点只能被经过一次,问题在于这题要求的是最多的经过的城市,这种要求两个信息的题粗略估计一下单纯的最大流做不了,是需要用到费用流的,给每个点i 到 i + N的边加上一个-1的cost,就可以用费用流直接维护出最多的城市了,方案的话相当于两遍dfs,搜索两条到终点的路径。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double eps = 1e-9;
const int maxn = 510;
const int maxm = 50010;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
string name[maxn];
map<string,int>P;
struct Edge{
    int to,nxt,cap,flow,cost;
    Edge(){}
    Edge(int to,int nxt,int cap,int flow,int cost):to(to),nxt(nxt),cap(cap),flow(flow),cost(cost){}
}edge[maxm * 2];
int n;
int head[maxn],tot;
void init(int x){
    n = x;
    for(int i = 0; i <= n; i ++) head[i] = -1;
}
void add(int u,int v,int w,int cost){
    edge[tot] = Edge(v,head[u],w,0,cost);
    head[u] = tot++;
    edge[tot] = Edge(u,head[v],0,0,-cost);
    head[v] = tot++;
}
int dis[maxn],vis[maxn],pre[maxn];
bool spfa(int s,int t){
    for(int i = 0 ; i <= n; i ++) dis[i] = INF,vis[i] = 0,pre[i] = -1;
    dis[s] = 0;
    queue<int>Q; Q.push(s);
    while(!Q.empty()){
        int u = Q.front(); Q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i ; i = edge[i].nxt){
            int v = edge[i].to;
            if(edge[i].cap <= edge[i].flow) continue;
            if(dis[v] > dis[u] + edge[i].cost){
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if(!vis[v]){
                    vis[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
    return ~pre[t];
}
int mcmf(int s,int t,int &cost){
    cost = 0;
    int flow = 0;
    while(spfa(s,t)){
        int Min = INF;
        for(int i = pre[t]; ~i; i = pre[edge[i ^ 1].to]){
            Min = min(Min,edge[i].cap - edge[i].flow);
        }
        flow += Min;
        for(int i = pre[t]; ~i ; i = pre[edge[i ^ 1].to]){
            edge[i].flow += Min;
            edge[i ^ 1].flow -= Min;
            cost += Min * edge[i].cost;
        }
    }
    return flow;
}
void dfs1(int t){
    cout << name[t] << endl;
    if(t == N) return;
    t += N;
    for(int i = head[t]; ~i ; i = edge[i].nxt){
        int v = edge[i].to;
        if(edge[i].flow >= 1){
            edge[i].flow -= 1;
            edge[i ^ 1].flow += 1;
            dfs1(v);
            return;
        }
    }
}
void dfs2(int t){
    if(t == N) return;
    t += N;
    for(int i = head[t]; ~i ; i = edge[i].nxt){
        int v = edge[i].to;
        if(edge[i].flow >= 1){
            edge[i].flow -= 1;
            edge[i ^ 1].flow += 1;
            dfs2(v);
            cout << name[t - N] << endl;
            return;
        }
    }
}
void show(){
    dfs1(1);
    dfs2(1);
}
int main(){
    Sca2(N,M);
    int S = 2 * N + 1,T = 2 * N + 2;
    init(T);
    for(int i = 1; i <= N ; i ++){
        cin >> name[i]; P[name[i]] = i;
        add(i,i + N,1,-1);
    }
    add(1,1 + N,1,0);
    add(N,N + N,1,0);
    add(S,1,INF,0); add(N + N,T,INF,0);
    for(int i = 1; i <= M ; i ++){
        string a,b;
        cin >> a >> b;
        int u = P[a],v = P[b];
        if(u > v) swap(u,v);
        add(u + N,v,INF,0);    
    }
    int cost;
    if(mcmf(S,T,cost) != 2){
        puts("No Solution!");
    }else{
        Pri(-cost);
        show();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Hugh-Locke/p/10359523.html
今日推荐