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

来源:互联网 发布:知画生孩子是第几集 编辑:程序博客网 时间:2024/05/18 03:21

问题描述:

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

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


编程任务:

对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。


数据输入:

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


结果输出:

输出第 1 行是旅行路线中所访问的城市总数 M 。接下来的 M1 行是旅行路线的城市名,每行写 1 个城市名。首先是出发城市名,然后按访问顺序列出其它城市名。注意,最后 1 行(终点城市)的城市名必然是出发城市名。如果问题无解,则输出“ No Solution! ” 。


输入文件示例:

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


输出文件示例:

7
Va
ncouver
Edmonton
Montreal
Halifax
To
ronto
Winnipeg
Calgary
Va
ncouver


分析:

题目的输入变态,一堆字符,所以我用了 map 。题目要求从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市),其实也就是说要求图中的流量为 2 。要求途经城市最多的旅行路线,其实就是要求跑最大流。
再说建模,因为除起点外任何城市只能访问 1 次,所以就要拆点,再想一想,因为整张图的流量必须为 2 ,所以终点也能访问多次。所以 对于第 i 个城市,我们将 i 拆成 i0i1 ,如果 i1in ,那么从 i0i1 连接一条容量为 1 ,权值为 1 的有向边,对于两座城市 i,j(i<j) ,如果它们之间有直通航线,那么,从 i1j0 连接一条容量为 1 ,权值为 0 的有向边,图中源点为 11 ,汇点为 n0
最后求出最小费用最大流即可。
但是,如果图中流量小于 2 ,但是如果第 1 个城市和第 n 个城市也有直通航线,那么这种情况也是可以的。


代码:

#include <cstdio>#include <algorithm>#include <cstring>#include <queue>#include <map>#include <iostream>#include <string>using namespace std;const int inf = 0x3f3f3f3f;map<string,int>turn;queue<int >que;int head[247],nxt[4747],to[4747],wei[4747],cost[4747],cot[4747],tot=1;int dis[247],pre[247],pres[247];bool vis[247];int way[3][247];int n,m;bool flag ;int ans,used;string str[247],s1,s2;void add(int,int,int,int);bool spfa();void doit();void get_way(int,int);int main(){    cin >> n >> m;    for(int i=1;i<=n;++i){        cin >> str[i];        turn.insert(pair<string,int>(str[i],i));        if(i!=1 && i!=n)            add(i<<1,(i<<1)+1,-1,i);    }    for(int i=1;i<=m;++i){        cin >> s1 >> s2;        if(turn[s1] > turn[s2])            swap(s1,s2);        if(turn[s1]==1 && turn[s2]==n)            flag = true;        add((turn[s1]<<1)+1,turn[s2]<<1,0,-1);    }    while(ans<2 && spfa()){        doit();        ++ans;    }    if(flag && !ans)        cout << 2 << endl << str[1] << endl << str[n] << endl << str[1];    else if(flag && ans==1){        way[1][++way[1][0]] = 1;        get_way(1,3);        cout << -used+2 << endl;        for(int i=1;i<=way[1][0];++i)            cout << str[way[1][i]] << endl;        cout << str[n] << endl << str[1];    }    else if(ans<2)        cout << "No Solution!";    else{        way[1][++way[1][0]] = way[2][++way[2][0]] = 1;        get_way(1,3);        get_way(2,3);        cout << -used+2 << endl;        for(int i=1;i<=way[1][0];++i)            cout << str[way[1][i]] << endl;        cout << str[n] << endl;        for(int i=way[2][0];i>=1;--i)            cout << str[way[2][i]] << endl;    }    return 0;}void add(int from,int tp,int spend,int i){    ++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;wei[tot]=1;cost[tot]=spend;cot[tot]=i;    ++tot;nxt[tot]=head[tp];head[tp]=tot;to[tot]=from;wei[tot]=0;cost[tot]=-spend;cot[tot]=-1;}bool spfa(){    memset(dis,0x3f,sizeof dis);    dis[3] = 0;    que.push(3);    int now;    do{        now = que.front();        vis[now] = false;        que.pop();        for(int i=head[now];i;i=nxt[i])            if(dis[to[i]]>dis[now]+cost[i] && wei[i]){                dis[to[i]] = dis[now]+cost[i];                pre[to[i]] = now;                pres[to[i]] = i;                if(!vis[to[i]]){                    vis[to[i]] = true;                    que.push(to[i]);                }            }    }while(!que.empty());    return dis[n<<1]!=inf;}void doit(){    used += dis[n<<1];    int now = n<<1;    while(now != 3){        --wei[pres[now]];        ++wei[pres[now]^1];        now = pre[now];    }}void get_way(int cnt,int place){    if(place == (n<<1))        return ;    for(int i=head[place];i;i=nxt[i])        if(!(i&1) && !wei[i] && !vis[to[i]]){            if(cot[i] != -1)                way[cnt][++way[cnt][0]] = cot[i];            vis[to[i]] = true;            get_way(cnt,to[i]);            return ;            }}
0 0
原创粉丝点击