網絡流與線性規劃24題11航空路線問題

問題描述:

給定一張航空圖,圖中頂點代表城市,邊代表2城市間的直通航線。現要求找出一條滿

足下述限制條件的且途經城市最多的旅行路線。
(1)從最西端城市出發,單向從西向東途經若干城市到達最東端城市,然後再單向從東
向西飛回起點(可途經若干城市)。
(2)除起點城市外,任何城市只能訪問1次。
編程任務:
對於給定的航空圖,試設計一個算法找出一條滿足要求的最佳航空旅行路線。
數據輸入:
由文件input.txt提供輸入數據。文件第1 行有2個正整數N 和V,N 表示城市數,N<100,
V 表示直飛航線數。接下來的N行中每一行是一個城市名,可乘飛機訪問這些城市。城市名
出現的順序是從西向東。也就是說,設i,j 是城市表列中城市出現的順序,當i>j 時,表示
城市i 在城市j 的東邊,而且不會有2 個城市在同一條經線上。城市名是一個長度不超過
15 的字符串,串中的字符可以是字母或阿拉伯數字。例如,AGR34或BEL4。
再接下來的V 行中,每行有2 個城市名,中間用空格隔開,如 city1 city2 表示city1
到city2 有一條直通航線,從city2 到city1 也有一條直通航線。
結果輸出:
程序運行結束時,將最佳航空旅行路線輸出到文件output.txt 中。文件第1 行是旅行路
線中所訪問的城市總數M。接下來的M+1 行是旅行路線的城市名,每行寫1 個城市名。首
先是出發城市名,然後按訪問順序列出其它城市名。注意,最後1行(終點城市)的城市名
必然是出發城市名。如果問題無解,則輸出“No Solution!”。
輸入示例                          輸出示例
8 9                                     7
Vancouver                        Vancouver
Yellowknife                      Edmonton
Edmonton                        Montreal
Calgary                             Halifax
Winnipeg                          Toronto
Toronto                             Winnipeg
Montreal                           Calgary
Halifax                               Vancouver
Vancouver Edmonton
Vancouver Calgary
Calgary Winnipeg
Winnipeg Toronto
Toronto Halifax
Montreal Halifax
Edmonton Montreal
Edmonton Yellowknife

Edmonton Calgary

分析:

這題建網絡流模型比較簡單,就是求出兩條最長不相交的增廣路。最大費用最大流可解,除了起點和終點每個點容量爲1,起點終點容量爲2,這樣就可以限制每個點只能取一次。點的容量如何爲1和2呢,之前有說過,把一個點拆成2個點,2點之間加邊,權值爲1或者2即可。對於每條航線,只要增加從西到東的航線就行了,因爲給出2個城市不一定是從西向東的順序,因此要判斷一下,航線容量爲1,費用爲0。值得注意的是起點和終點城市容量爲2,在極端情況下只有2個城市a,b,如果容量爲1就錯了,因爲可以這樣的情況:a->b->a。求一次最大費用流就可以了。起點是1,終點是n。因爲求出的是最大流,所以保證在可能的情況下流量一定爲2,如果流量爲1或者0,則No Solution!。

可以轉化爲最小費用流,方法很簡單就是把費用從正變爲負,這樣求出的最小費用取負就是最大費用流。求增廣路還是用spfa。

有人會疑惑,不是從西到東再到西麼。換個角度想就是2條從西向東的路,起點終點相同。

不過打印路線還是比較麻煩的,用一個visit數組判斷是否打印過這個點,因爲一共有2條路線。具體的看代碼實現吧。

代碼:

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1001;
const int INF = 1<<30;
struct edge{
    int from,to,cap,flow,cost;
    edge(int a,int b,int c,int d,int e):from(a),to(b),cap(c),flow(d),cost(e){}
};
int s,t;
int n,m;
bool inqueue[maxn];
int p[maxn],d[maxn],a[maxn];
char city[maxn>>1][16];
bool visit[maxn];
vector<int> g[maxn];
vector<edge> edges;
void addedge(int from,int to,int cap,int cost)
{
    edges.push_back(edge(from,to,cap,0,cost));
    edges.push_back(edge(to,from,0,0,-cost));
    int k=edges.size();
    g[from].push_back(k-2);
    g[to].push_back(k-1);
}
int geti(char *s)
{
    int i=1;
    while(i<=n && strcmp(s,city[i]))
        i++;
    return i;
}
bool spfa(int &flow,int &cost)
{
    memset(inqueue,false,sizeof(inqueue));
    for(int i=s;i<=t;i++) d[i]=INF;
    d[s]=0;inqueue[s]=true;a[s]=INF;p[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty()){
        int x=q.front();q.pop();inqueue[x]=false;
        for(int i=0;i<g[x].size();i++){
            edge &e=edges[g[x][i]];
            if(e.cap>e.flow && d[e.to]>d[x]+e.cost){
                d[e.to]=d[x]+e.cost;
                p[e.to]=g[x][i];
                a[e.to]=min(a[x],e.cap-e.flow);
                if(!inqueue[e.to]){
                    q.push(e.to);
                    inqueue[e.to]=true;
                }
            }
        }
    }
    if(d[t]==INF) return false;

    flow+=a[t];
    cost+=a[t]*d[t];
    int x=t;
    while(x!=s){
        edges[p[x]].flow+=a[t];
        edges[p[x]^1].flow-=a[t];
        x=edges[p[x]].from;
    }
    return true;
}
int mincost()
{
    int flow=0,cost=0;
    while(spfa(flow,cost));
    return cost;
}
void printans(int cost)
{
    printf("%d\n",cost);
    int x=1+n;
    printf("%s\n",city[1]);
    while(x!=t){
        for(int i=0;i<g[x].size();i++){
            edge &e=edges[g[x][i]];
            if(e.flow==1&&!visit[e.to]){
                visit[e.to]=true;
                printf("%s\n",city[e.to]);
                x=e.to+n;
                break;
            }
        }
    }
    x=n;
    while(x!=s){
        for(int i=0;i<g[x].size();i++){
            edge &e=edges[g[x][i]^1];
            if(e.flow==1 && !visit[e.from-n]){
                x=e.from-n;
                visit[x]=true;
                printf("%s\n",city[x]);
                break;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        if(i==1||i==n) addedge(i,i+n,2,-1);
        else addedge(i,i+n,1,-1);
    }
    for(int i=1;i<=n;i++)
        scanf("%s",city[i]);

    char from[16],to[16];
    for(int i=1;i<=m;i++){
        scanf("%s%s",from,to);
        int f=geti(from),o=geti(to);
        int m=min(f,o);
        int k=o+f-m;
        if(m==1&&k==n) addedge(m+n,k,2,0);
        else addedge(m+n,k,1,0);
    }
    s=1;t=n+n;
    int cost=-2-mincost();
    if(edges[g[s][0]].flow!=2) printf("No Solution!\n");
    else  printans(cost);
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章