网络流24题——航空路线问题(最长不相交路径)

链接:https://www.oj.swust.edu.cn/oj/problem/show/1746

题意:给定无向图,求一条从s到t再到s的最长路径,除s外每个点最多经过一次。

分析:实际上相当于求两条从s到t的路径,两条路径互不相交且长度和最大。先拆点,把每个点拆成X和Y,连一条容量为1、费用为-1的边,再求一次最小费用最大流。最大流不为2时无解。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<vector>
  5 #include<queue>
  6 #include<stack>
  7 #include<map>
  8 #include<string>
  9 using namespace std;
 10 typedef long long ll;
 11 const int maxn=205,INF=1e9;
 12 int n,v;
 13 map<string,int> city;
 14 string name[maxn];
 15 struct Edge{
 16     int from,to,cap,flow,cost;
 17     Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}
 18 };
 19 struct MCMF{
 20     int n,s,t;
 21     vector<Edge> edges;
 22     vector<int> G[maxn];
 23     int inq[maxn],d[maxn],p[maxn],a[maxn];
 24     ll flow,cost;
 25     void init(int n){
 26         this->n=n;
 27         flow=0,cost=0;
 28         for(int i=0;i<n;i++)G[i].clear();
 29         edges.clear();
 30     }
 31 
 32     void AddEdge(int from,int to,int cap,int cost){
 33         edges.push_back(Edge(from,to,cap,0,cost));
 34         edges.push_back(Edge(to,from,0,0,-cost));
 35         G[from].push_back(edges.size()-2);
 36         G[to].push_back(edges.size()-1);
 37     }
 38 
 39     bool spfa(int s,int t){
 40         this->s=s;this->t=t;
 41         for(int i=0;i<n;i++)d[i]=INF;
 42         memset(inq,0,sizeof(inq));
 43         d[s]=0;inq[s]=1;p[s]=0;a[s]=INF;
 44         queue<int>Q;
 45         Q.push(s);
 46         while(!Q.empty()){
 47             int u=Q.front();Q.pop();
 48             inq[u]=0;
 49             for(int i=0;i<G[u].size();i++){
 50                 Edge& e=edges[G[u][i]];
 51                 if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
 52                     d[e.to]=d[u]+e.cost;
 53                     p[e.to]=G[u][i];
 54                     a[e.to]=min(a[u],e.cap-e.flow);
 55                     if(!inq[e.to]){Q.push(e.to);inq[e.to]=1;}
 56                 }
 57             }
 58         }
 59         if(d[t]==INF)return false;
 60         flow+=a[t];cost+=d[t]*a[t];
 61         int u=t;
 62         while(u!=s){
 63             edges[p[u]].flow+=a[t];
 64             edges[p[u]^1].flow-=a[t];
 65             u=edges[p[u]].from;
 66         }
 67         return true;
 68     }
 69     ll Mincost(int s,int t){
 70         while(spfa(s,t));
 71         return cost;
 72     }
 73     void Print(int n){
 74         int have[maxn];
 75         memset(have,0,sizeof(have));
 76         cout<<name[1]<<endl;
 77         int u=s+n;
 78         while(u!=t+n){
 79             for(int i=0;i<G[u].size();i++){
 80                 Edge &e=edges[G[u][i]];
 81                 if(e.flow>=1&&have[e.to]==0){
 82                     have[e.to]=1;
 83                     cout<<name[e.to]<<endl;
 84                     u=e.to+n;break;
 85                 }
 86             }
 87             if(u==s+n)break;
 88         }
 89         u=n;
 90         while(u!=s){
 91             for(int i=0;i<G[u].size();i++){
 92                 Edge &e=edges[G[u][i]^1];
 93                 if(e.flow>=1&&have[e.from-n]==0){
 94                     have[e.from-n]=1;
 95                     cout<<name[e.from-n]<<endl;
 96                     u=e.from-n;break;
 97                 }
 98             }
 99             if(u==n)break;
100         }
101     }
102 }mcmf;
103 int main(){
104 //    freopen("e:\\in.txt","r",stdin);
105     string s,t;
106     scanf("%d%d",&n,&v);
107     mcmf.init(2*n);
108     mcmf.AddEdge(1,1+n,2,0);
109     for(int i=2;i<n;i++)mcmf.AddEdge(i,i+n,1,-1);
110     for(int i=1;i<=n;i++){
111         cin>>s;
112         city[s]=i;
113         name[i]=s;
114     }
115     for(int i=0;i<v;i++){
116         cin>>s>>t;
117         mcmf.AddEdge(city[s]+n,city[t],INF,0);
118     }
119     int ans=2-mcmf.Mincost(1,n);
120     if(mcmf.flow!=2){
121         printf("No Solution!\n");
122     }else{
123         printf("%d\n",ans);
124         mcmf.Print(n);
125     }
126     return 0;
127 }

 

转载于:https://www.cnblogs.com/7391-KID/p/7448277.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值