1. 程式人生 > >2018.10.22【網路流24題】【洛谷P2770】【LOJ6122】航空路線問題(費用流)

2018.10.22【網路流24題】【洛谷P2770】【LOJ6122】航空路線問題(費用流)

洛谷傳送門

解析:

調了半天最後發現費用流部分一個小細節跪了。。。 心態爆炸。。。問題不大

思路:

首先我們直接找出兩條沒有重複節點的路徑,一條正著輸出一條倒著輸出就行了。

找的話考慮網路流。我們將每個點拆點成兩個ai,bia_i,b_i,為保證每個城市只在路徑中出現一次,我們從aia_ibib_i連一條容量為11的邊,但是注意節點11和節點nn需要連容量為22的邊,因為需要兩條路徑。

對於每條邊<u,v><u,v>我們從bub_uava_v連邊,容量為11,這個是路徑存在性問題的老套路了。

如果最後跑出來的最大流為0,則根本不存在從11nn的路徑。

否則,一定存在。 為了使經過的城市最多,我們在每個aia_ibib_i的邊上賦費用為11,即要求最大費用,使得這個城市被經過就有一份費用被記錄在答案中。(轉成-1求最小費用)

那麼最大費用減去在11nn的兩次經過,就是經過的城市數。

怎麼找路徑?

考慮我們走過的路徑才會有流量,那麼它的反向邊的流量就是我們經過它的次數,直接從源點dfs一下,同時清空一下流量就行了。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register #define gc getchar #define pc putchar #define cs const cs int N=203,M=20004,INF=0x3f3f3f3f; int last[N],nxt[M<<1],to[M<<1],ecnt=1; int cap[M<<1],w[M<<1]; inline void addedge(int u,int v,int val,int cost){ nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,cap[ecnt]
=val,w[ecnt]=cost; nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,cap[ecnt]= 0 ,w[ecnt]=-cost; } int S,T; int dist[N]; int cur[N]; bool vis[N]; queue<int> q; inline bool SPFA(){ memset(dist,0x3f,sizeof dist); memset(vis,0,sizeof vis); dist[S]=0; q.push(S); cur[S]=last[S]; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=false; for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){ if(cap[e]&&dist[v]>dist[u]+w[e]){ dist[v]=dist[u]+w[e]; if(!vis[v]){ vis[v]=true; q.push(v); cur[v]=last[v]; } } } } return dist[T]<INF; } int dfs(cs int &u,cs int &flow,int &maxc){ if(u==T){ maxc+=flow*dist[T]; return flow; } int ans=0; vis[u]=true; for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){ if(cap[e]&&!vis[v]&&dist[v]==dist[u]+w[e]){ int delta=dfs(v,min(flow-ans,cap[e]),maxc); if(delta){ cap[e]-=delta; cap[e^1]+=delta; ans+=delta; if(ans==flow)return flow; } } } return ans; } int maxf,maxc; inline pair<int,int> MCMF(){ maxf=0;maxc=0; while(SPFA())maxf+=dfs(S,INF,maxc); return make_pair(maxf,maxc); } map<string,int> id; string name[N>>1],s1,s2; int n,m; int ans[N],tot; void getans(int u){ ans[++tot]=u; for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){ if(e&1)continue; if(cap[e^1]){ --cap[e^1]; getans(v); return ; } } } signed main(){ ios::sync_with_stdio(false); cin>>n>>m; for(int re i=1;i<=n;++i){ cin>>name[i]; id[name[i]]=i; } S=0,T=n+n+1; addedge(S,1,2,0); addedge(1,1+n,1,-1); addedge(n,n+n,1,-1); addedge(n+n,T,2,0); for(int re i=1;i<=m;++i){ cin>>s1>>s2; int u=id[s1],v=id[s2]; if(u>v)swap(u,v); addedge(u+n,v,INF,0); } for(int re i=1;i<=n;++i)addedge(i,i+n,1,-1); MCMF(); if(maxf==0)return cout<<"No Solution!\n",0; cout<<(-maxc-2)<<"\n"; getans(1); for(int re i=1;i<=tot;++i)if(ans[i]&&ans[i]<=n)cout<<name[ans[i]].c_str()<<endl; tot=0; getans(1); bool flag=0; for(int re i=tot;i;--i){ if(ans[i]&&ans[i]<=n) if(flag)cout<<name[ans[i]].c_str()<<endl; else flag=true; } return 0; }