2018.10.22【網路流24題】【洛谷P2770】【LOJ6122】航空路線問題(費用流)
阿新 • • 發佈:2018-12-16
洛谷傳送門
解析:
調了半天最後發現費用流部分一個小細節跪了。。。 心態爆炸。。。問題不大
思路:
首先我們直接找出兩條沒有重複節點的路徑,一條正著輸出一條倒著輸出就行了。
找的話考慮網路流。我們將每個點拆點成兩個,為保證每個城市只在路徑中出現一次,我們從向連一條容量為的邊,但是注意節點和節點需要連容量為的邊,因為需要兩條路徑。
對於每條邊我們從向連邊,容量為,這個是路徑存在性問題的老套路了。
如果最後跑出來的最大流為0,則根本不存在從到的路徑。
否則,一定存在。 為了使經過的城市最多,我們在每個到的邊上賦費用為,即要求最大費用,使得這個城市被經過就有一份費用被記錄在答案中。(轉成-1求最小費用)
那麼最大費用減去在和的兩次經過,就是經過的城市數。
怎麼找路徑?
考慮我們走過的路徑才會有流量,那麼它的反向邊的流量就是我們經過它的次數,直接從源點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;
}