• [网络流24题]航空路线问题


    Description

    给定一张航空图,图中顶点代表城市,边代表$2$城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。

    • 从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
    • 除起点城市外,任何城市只能访问$1$次。

    求一条满足要求的最佳航空旅行路线。

    Input

    第$1$行有$2$个正整数$N,V$,$N$表示城市数,$V$表示直飞航线数。

    接下来的$N$行中每一行是一个城市名,可乘飞机访问这些城市。城市名出现的顺序是从西向东。也就是说,设$i,j$是城市表列中城市出现的顺序,当$i>j$时,表示城市$i$在城市$j$的东边,而且不会有$2$个城市在同一条经线上。城市名是一个长度不超过$15$的字符串,串中的字符可以是字母或阿拉伯数字。例如,$AGR34,BEL4$。
    再接下来的$V$行中,每行有$2$个城市名,中间用空格隔开,如$city1;;city2$表示$city1$到$city2$有一条直通航线,从$city2$到$city1$也有一条直通航线。

    Output

    第$1$行是旅行路线中所访问的城市总数$M$。

    接下来的$M+1$行是旅行路线的城市名,每行写$1$个城市名。首先是出发城市名,然后按访问顺序列出其它城市名。注意,最后$1$行(终点城市)的城市名
    必然是出发城市名。

    如果问题无解,则输出“$No Solution!$” 。
    Sample Input

    8 9
    Vancouver
    Yellowknife
    Edmonton
    Calgary
    Winnipeg
    Toronto
    Montreal
    Halifax
    Vancouver Edmonton
    Vancouver Calgary
    Calgary Winnipeg
    Winnipeg Toronto
    Toronto Halifax
    Montreal Halifax
    Edmonton Montreal
    Edmonton Yellowknife
    Edmonton Calgary

    Sample Output

    7
    Vancouver
    Edmonton
    Montreal
    Halifax
    Toronto
    Winnipeg
    Calgary
    Vancouver

    HINT

    $N<100$

    Solution

    为了限制经过次数,将每个点$i$拆成$x_i,y_i$.

    从$x_i$向$y_i$连一条容量为$1$,费用为$1$的有向边($1<i<N$),

    从$x_1$向$y_1$连一条容量为$2$,费用为$1$的有向边,

    从$x_N$向$y_N$连一条容量为$2$,费用为$1$的有向边,

    如果存在边($i,j$)($i<j$)从$y_i$向$x_j$连一条容量为$1$,费用为$0$的有向边.

    求$x_1$到$y_N$的最大费用最大流.若($x_1,y_1$)满流,则有解,答案为最大费用最大流$-2$;否则,无解.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define L 20
    #define N 55
    using namespace std;
    struct graph{
        int nxt,to,f,w;
    }e[N*N<<1]; 
    struct edge{
        int e,v;
    }pre[N*N<<1];
    int g[N<<1],dis[N<<1],nxt[N<<1],n,m,s,t,cnt=1,ans;
    bool v[N],inq[N<<1];char c[N][L],l[L];
    queue<int> q;
    inline void addedge(int x,int y,int f,int w){
        e[++cnt].nxt=g[x];g[x]=cnt;
        e[cnt].to=y;e[cnt].f=f;e[cnt].w=w;
    }
    inline void adde(int x,int y,int f,int w){
        addedge(x,y,f,w);addedge(y,x,0,-w);
    }
    inline bool spfa(int u){
        memset(dis,0,sizeof(dis));
        memset(inq,0,sizeof(inq)); 
        q.push(u);inq[u]=true;
        while(!q.empty()){
            u=q.front();q.pop();inq[u]=false;
            for(int i=g[u];i;i=e[i].nxt){
                if(e[i].f>0&&dis[u]+e[i].w>dis[e[i].to]){
                    dis[e[i].to]=dis[u]+e[i].w;
                    pre[e[i].to].e=i;pre[e[i].to].v=u;
                    if(!inq[e[i].to]){
                        inq[e[i].to]=true;q.push(e[i].to);
                    }
                }
            }
        }
        return dis[t];
    } 
    inline int mf(int f){
        int ret=0,d;
        while(f){
            if(!spfa(s)) return -1;
            d=f;
            for(int i=t;i!=s;i=pre[i].v)
                d=min(e[pre[i].e].f,d);
            ret+=d*dis[t];f-=d;
            for(int i=t;i!=s;i=pre[i].v){
                e[pre[i].e].f-=d;e[pre[i].e^1].f+=d;
            }
        }
        return ret;
    } 
    inline void Aireen(){
        scanf("%d%d",&n,&m);
        s=1;t=n<<1;
        for(int i=1;i<=n;++i)
            scanf("%s",c[i]);
        for(int i=1,j,k,tmp;i<=m;++i){
            scanf("%s",l);
            for(j=1;strcmp(l,c[j]);++j);
            scanf("%s",l);
            for(k=1;strcmp(l,c[k]);++k);
            if(j>k){
                tmp=j;j=k;k=tmp;
            }
            if(j==1&&k==n) adde(j+n,k,2,0);
            else adde(j+n,k,1,0);
        }
        adde(1,1+n,2,1);
        adde(n,n<<1,2,1);
        for(int i=2;i<n;++i)
            adde(i,i+n,1,1);
        ans=mf(2);
        if(ans<0){
            puts("No Solution!");
            return;
        }
        printf("%d
    ",ans-2);
        printf("%s
    ",c[1]);
        for(int i=g[s+n],j,k;i;i=e[i].nxt)
            if(!e[i].f&&!(i&1)){
                k=e[i].to;
                while(k){
                    printf("%s
    ",c[k]);
                    v[k]=true;
                    for(j=g[k+n],k=0;j;j=e[j].nxt)
                        if(!e[j].f&&!(j&1)){
                            k=e[j].to;break;
                        }
                }
                break;
            }
        for(int i=g[t-n],j,k;i;i=e[i].nxt)
            if(!e[i^1].f&&(i&1)&&!v[e[i].to-n]){
                k=e[i].to-n;
                while(k){
                    printf("%s
    ",c[k]);v[k]=true;
                    for(j=g[k],k=0;j;j=e[j].nxt)
                        if(!e[j^1].f&&(j&1)){
                            k=e[j].to-n;break;
                        }
                }
                break;
            }
    }
    int main(){
        freopen("airl.in","r",stdin);
        freopen("airl.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    完毕port(CompletionPort)具体解释
    [Java聊天室server]实战之五 读写循环(服务端)
    ImageMagick的安装及使用
    STL学习小结
    ORACLE中%TYPE和%ROWTYPE的使用
    命令模式在MVC框架中的应用
    代码阅读分析工具Understand 2.0试用
    SimpleDateFormat 的线程安全问题与解决方式
    C++垃圾回收机制
    TH文字编辑器开发的第一个游戏,唐伯虎泡妞
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6243290.html
Copyright © 2020-2023  润新知