【网络流24题之航空线路】(只求方案数)xoj1248

来源:互联网 发布:js如何获取select的值 编辑:程序博客网 时间:2024/05/22 13:39

题目描述

给定一张航空图,图中顶点代表城市,边代表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
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

题解

  • 根据题意,首先我们要找出题目的限制。就是每个城市做多只能经过一次(起点可以经过两次,我们把终点也看成可以经过两次)。可以用容量为1(两次为2)的边来限制,题目又要求经过最多城市,我们可以求一个最大费用流(插入费用时变负数,按照最小费用的过程来做,答案再取反)。建模比较容易,只需要将每个点拆成两个点,一个代表进入城市,一个代表离开城市,显然,城市之间的边容量可以为inf,花费为0(已经有S->ii->T的边限制)。
    具体代码
#include <iostream>#include <cstdio>#include <queue>#include <cstring>#include <map>#define _(d) while(d (((ch=getchar())>47)&&ch<58))using namespace std;const int MaxN=223,Maxe=MaxN*MaxN/2;const int inf=0x7fffffff;int N,V,ans,h[MaxN],pre[MaxN],vst[MaxN],d[MaxN];int S,T,tt,from[Maxe],to[Maxe],flow[Maxe],cst[Maxe],nxt[Maxe];string str[MaxN];map<string,int> hash;inline void Get(int &x){char ch;_(!);x=ch-48;_()x=(x<<3)+(x<<1)+ch-48;}inline void addedge(int u,int v,int w,int cc){    from[tt]=u;to[tt]=v;flow[tt]=w;cst[tt]=cc;    nxt[tt]=h[u];h[u]=tt++; }inline void add(int u,int v,int w,int cc){    addedge(u,v,w,cc);addedge(v,u,0,-cc);   }queue<int> q;bool spfa(){    for(int i=0;i<MaxN;i++) pre[i]=-1,vst[i]=0,d[i]=inf;    q.push(S);vst[S]=1;d[S]=0;    while(!q.empty())    {        int u=q.front();q.pop();        vst[u]=0;        for(int i=h[u];i!=-1;i=nxt[i])        {            int v=to[i];            if(flow[i]&&d[v]>d[u]+cst[i])            {                d[v]=d[u]+cst[i];                pre[v]=i;                if(!vst[v])                {                    q.push(v);                    vst[v]=1;                   }               }           }    }    return d[T]!=inf;}inline void work(){    int ft;    while(spfa())    {        ft=inf;        for(int i=T;i!=S;i=from[pre[i]]){ft=min(ft,flow[pre[i]]);}        for(int i=T;i!=S;i=from[pre[i]])        {            int k=pre[i];            flow[k]-=ft;            flow[k^1]+=ft;            ans+=cst[k]*ft;         }    }    return;}int main(){    for(int i=0;i<MaxN;i++) h[i]=-1;    string str1,str2;    Get(N);Get(V);    S=1;T=2*N;    add(S,S+N,2,-1);add(N,T,2,-1);    for(int i=1;i<=N;i++)    {        cin>>str[i];        hash[str[i]]=i;        if(i>1&&i<N) add(i,i+N,1,-1);    }    for(int i=1;i<=V;i++)    {        cin>>str1>>str2;        int a=hash[str1],b=hash[str2];        if(a>b) swap(a,b);        add(a+N,b,inf,0);       }    work();    if(flow[0]) printf("No Solution!\n");    else printf("%d\n",-2-ans);    return 0;   }
0 0
原创粉丝点击