【网络流24题】航空路线问题(最大费用流)

来源:互联网 发布:泰国直播软件 编辑:程序博客网 时间:2024/05/22 08:20

传送门

    航空路线问题
    题意:给定起终点,找出两条除起终点之外无相交点的最长路径.

I think

    最大费用流问题.拆点后对于直航< a,b>,仅当a< b时连边(若当a>b时也连边,则出现正环,SPFA无法求解),将点1与点N所连边流量设置为2,相当于找出两条除起点与终点之外无重合的路径.
    输出方案时只依靠pre回头找常常是行不通的,因为如果不特殊处理,你无法知道若干条流什么时候汇,什么时候分.因此还是”备份”一下边容量的初始状态,再dfs找有流经过的边.注意只选择正向边(i%2==0).
    类似数字梯形的某要求.

Code

#include<iostream>#include<cstdio>#include<string>#include<queue>#include<map>using namespace std;const int sm = 205;const int sn = 1e4;const int Inf = 0x3f3f3f3f;int N,M,S,T,tot=1;int to[sn],nxt[sn],hd[sm],c[sn],f[sn];int pre[sm],vis[sm],cst[sm],ord[sm];map<string,int>msi;map<int,string>mis;char ch[16],sh[16];int Min(int x,int y) { return x<y?x:y; }void Add(int u,int v,int x,int y) {    to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,c[tot]=x,f[tot]=y;    to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,c[tot]=0,f[tot]=-y;}void printa(int x,int ct) {    ord[++ct]=x;    if(x==T) {        for(int i=1;i<=ct;i+=2)            cout<<mis[ord[i]]<<endl;        return ;    }    for(int i=hd[x];i;i=nxt[i])        if(!c[i]&&i%2==0) {            printa(to[i],ct);            if(to[i]!=1&&to[i]!=N+1&&to[i]!=N&&to[i]!=N<<1)                c[i]=-1;            return ;        }}void printb(int x,int ct) {    ord[++ct]=x;    if(x==T) {        for(int i=ct-3;i>=1;i-=2)            cout<<mis[ord[i]]<<endl;        return ;    }    for(int i=hd[x];i;i=nxt[i])        if(!c[i]&&i%2==0) {            printb(to[i],ct);            return ;        }}void work() {    int t,df,Flw=0,Ans=0,u;    queue<int>q;    while(true) {        for(int i=1;i<=T;++i) cst[i]=-Inf;        q.push(S),cst[S]=0;        while(!q.empty()) {            t=q.front(),q.pop(),vis[t]=0;            for(int i=hd[t];i;i=nxt[i])                 if(c[i]>0&&cst[to[i]]<cst[t]+f[i]) {                    cst[to[i]]=cst[t]+f[i];                    pre[to[i]]=i;                    if(!vis[to[i]]) {                        vis[to[i]]=1;                        q.push(to[i]);                    }                }        }        if(cst[T]==-Inf) break;        df=Inf;        for(int i=T;i!=S;i=to[pre[i]^1])             df=Min(df,c[pre[i]]);        for(int i=T;i!=S;i=to[pre[i]^1])            c[pre[i]]-=df,c[pre[i]^1]+=df;        Flw+=df;        Ans+=cst[T]*df;    }    if(Flw<2) puts("No Solution!");    else {        printf("%d\n",Ans-2);        printa(S,0),printb(S,0);    }}int main() {    scanf("%d%d",&N,&M);    S=1,T=N<<1;    for(int i=1;i<=N;++i) {        scanf("%s",ch);        msi[ch]=i,mis[i]=ch;        if(i!=1&&i!=N) Add(i,i+N,1,1);        else Add(i,i+N,2,1);    }    for(int i=1;i<=M;++i) {        scanf("%s%s",ch,sh);        if(msi[ch]<msi[sh]) {            if(msi[ch]==S&&msi[sh]==N)                 Add(msi[ch]+N,msi[sh],2,0);            else Add(msi[ch]+N,msi[sh],1,0);        }        else {            if(msi[ch]==N&&msi[sh]==S)                 Add(msi[sh]+N,msi[ch],2,0);            else Add(msi[sh]+N,msi[ch],1,0);        }    }    work();    return 0;}
阅读全文
0 0
原创粉丝点击