1. 程式人生 > >洛谷P2770 雙路DP // 網絡流

洛谷P2770 雙路DP // 網絡流

head 操作 www init else 題目 eof tchar onclick

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;
}

洛谷P2770 雙路DP // 網絡流