• luogu P2770 航空路线问题


    题目链接

    luogu P2770 航空路线问题

    题解

    求两条点数最多的互不相交路径
    拆点限流,连流量1费用2的边,起.终点流量为2的边

    代码

    #include<bits/stdc++.h> 
    using namespace std; 
    inline int read() { 
        int x = 0,f = 1; char c = getchar(); 
        while(c < '0'  || c > '9')c = getchar(); 
        while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
        return x * f ; 
    } 
    #define INF 0x7fffffff
    const int  maxn  = 207; 
    const int  maxm  = 24007; 
    struct node {
        int u,v,cost,flow,next;
        node(int u = 0,int v = 0,int cost = 0,int flow = 0,int next = 0) : u(u), v(v), cost(cost), flow(flow), next(next) {} 
    } edge[maxm << 1]; 
    int head[maxn],num = 1; 
    void add_edge(int u,int v,int cost,int flow) {  edge[++ num] = node(u,v,cost,flow,head[u]); head[u] = num; } 
    queue<int>q; 
    bool vis[maxn];  
    int dis[maxn],path[maxn],pre[maxn]; 
    int n,m,S,T; 
    bool spfa() { 
        memset(dis,0x3f,sizeof dis);pre[S] = -1; 
        q.push(S),vis[S]=true,dis[S]=0; 
        while(!q.empty()) { 
            int u = q.front(); q.pop(); 
            for(int i = head[u];i;i = edge[i].next) { 
                int v = edge[i].v; 
                if(edge[i].flow > 0 && dis[v] > dis[u] + edge[i].cost) { 
                    dis[v] = edge[path[v] = i].cost + dis[pre[v] = u]; 
                    if(!vis[v])  q.push(v) , vis[v]=true;  
                } 
            } vis[u] = false; 
        } 
        return dis[T] != 0x3f3f3f3f; 
    } 
    
    int maxflow,mincost; 
    void calc() {
        int f = INF;
        for(int u = T;u != S;u = pre[u])  f = min(f,edge[path[u]].flow); 
        maxflow += f,mincost += dis[T] * f; 
        for(int u = T;u != S;u = pre[u]) {  
           edge[path[u]].flow -= f,  
           edge[path[u] ^ 1].flow += f;  
        } 
    } 
    void MCMF() { 
        while(spfa())  calc();  
    } 
    bool flag[maxn]; 
    map<string,int>mp; 
    map<int,string>rmp; 
    int main() {
        n = read(),m = read(); 
        S = 1,T = n << 1;
        for(int i = 1;i <= n;i ++) { 
        	string s; 
            cin >> s; mp[s] = i; rmp[i] = s; 
            if(i == 1 || i == n) add_edge(i,i + n,-1,2) , add_edge(i + n,i,1,0); 
            else add_edge(i,i+n,-1,1),add_edge(i+n,i,1,0);
        } 
        for(int i = 1;i <= m;i ++) { 
            string a,b; 
            cin >> a >> b; 
            int u = mp[a],v = mp[b]; 
            if(v < u) swap(u , v); 
            if(u == 1 && v == n) add_edge(u + n,v,0,2) , add_edge(v,u + n,0,0); 
            else add_edge(u + n,v,0,1) , add_edge(v,u + n,0,0);  
        } 
        MCMF(); 
        if(edge[2].flow != 0) { puts("No Solution!"); return 0; }  
        cout << -mincost - 2 << endl << rmp[1] << endl; 
        for(int i = head[n + 1];i;i = edge[i].next)   
            if(! edge[i].flow && ! (i & 1)) { 
                for(int v = edge[i].v, j ; v ;) {  
                    cout << rmp[v] << endl; 
                    flag[v] = true;  
                    for(j = head[v + n],v = 0;j;j = edge[j].next) 
                        if(! edge[j].flow && ! (j & 1)) { 
                            v = edge[j].v; 
                            break; 
                        } 
                } 
                break; 
            } 
        for(int i = head[n];i;i = edge[i].next) 
            if(! edge[i ^ 1].flow && (i & 1) && ! flag[edge[i].v - n]) { 
                for(int v = edge[i].v - n,j;v;) { 
                    cout << rmp[v] << endl;flag[v] = true; 
                    for(j = head[v],v = 0;j;j = edge[j].next) 
                        if(! edge[j ^ 1].flow && (j & 1)) { 
                            v = edge[j].v - n; 
                            break; 
                        } 
                } 
                break; 
            } 
        return 0; 
    } 
    
    
  • 相关阅读:
    导弹拦截版
    [USACO1.5]数字三角形 Number Triangles
    FBI树
    修复公路
    台阶问题
    阶乘问题
    连续自然数和
    又是毕业季I
    生活大爆炸版石头剪刀布
    曹冲养猪
  • 原文地址:https://www.cnblogs.com/sssy/p/9357034.html
Copyright © 2020-2023  润新知