[网络流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\n",ans-2);
    printf("%s\n",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\n",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\n",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;
}
posted @ 2017-01-02 21:49  Aireen_Ye  阅读(826)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.