洛谷 - P2770 航空路线问题(最大费用最大流+路径打印)
題目鏈接:點擊查看
題目大意:給出一個由n個點及m條邊組成的無向圖,現在要求從點1出發,到達點n,再回到點1,一路上經過盡可能多的點,并且保證除了起點和終點外的每個點至多只能經過一次,并輸出路徑
題目分析:從點1出發到點n再回到點1,這個題目之前做過類似的,不過那個題目是要求最短路,用的是最小費用最大流,回到這個題目來看,要求盡可能多的經過點,也就說明每個點對答案的貢獻為1,所以要用最大費用最大流,而權值在點上,很自然的想到需要拆點限流,所以建圖方式就出來了:
如此建圖后,直接跑最大費用最大流就可以進一步判斷了,現在可以得到了一個ans代表的最大花費,以及max_flow代表最大流,顯然當最大流等于2的時候說明可以在原圖中找到兩條不想交的從起點到終點的路徑,此時的花費為ans-2,因為起點和終點被計算了兩次,所以減去2就好了,max_flow不等于2的時候直接輸出No Solution!就好了,但是真的是這樣嗎?如果這樣判斷交上去有一個測試點過不去,這就是這個題目的一個小坑了,如果整張圖中只有一條路徑是從點1直接到點n的,這樣的圖雖然max_flow等于1,但是卻是符合條件的特例,需要特判一下
現在只是判斷出是否有解,最后還需要輸出路徑,其實直接跑dfs就好了,因為每條連邊的流量都設置為1,所以如果這條邊對答案做出了貢獻,那么他的流量就會變成0,對于每個點尋找一下他的下一個符合要求的點,一路尋找,從起點找到終點就好了,記得用一個vis數組標記一下哪些點已經使用過了,因為對于每個點至多只能使用一次嘛,第一遍dfs正序輸出,第二遍dfs倒序輸出,寫法類似于樹的前序遍歷和后序遍歷,剩下的對于細節仔細處理一下就好了
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;//點const int M=1e5+100;//邊unordered_map<string,int>mp;string str[N];struct Edge {int to,w,cost,next; }edge[M];int head[N],cnt,max_flow,n,m,st=N-1,ed=st-1;void addedge(int u,int v,int w,int cost) {edge[cnt].to=v;edge[cnt].w=w;edge[cnt].cost=cost;edge[cnt].next=head[u];head[u]=cnt++;edge[cnt].to=u;edge[cnt].w=0;edge[cnt].cost=-cost;edge[cnt].next=head[v];head[v]=cnt++; }int d[N],incf[N],pre[N];bool vis[N];bool spfa(int s,int t) {memset(d,0xcf,sizeof(d));memset(vis,false,sizeof(vis));memset(pre,-1,sizeof(pre));queue<int>q;q.push(s);vis[s]=true;incf[s]=inf;d[s]=0;while(!q.empty()){int u=q.front();q.pop();vis[u]=false;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;int cost=edge[i].cost;if(!w)continue;if(d[v]<d[u]+cost){d[v]=d[u]+cost;pre[v]=i;incf[v]=min(incf[u],w);if(!vis[v]){vis[v]=true;q.push(v);}}}}return pre[t]!=-1; }int update(int s,int t) {int x=t;while(x!=s){int i=pre[x];edge[i].w-=incf[t];edge[i^1].w+=incf[t];x=edge[i^1].to;}max_flow+=incf[t];return d[t]*incf[t]; }void init() {memset(head,-1,sizeof(head));cnt=0; }int solve(int st,int ed) {int ans=0;while(spfa(st,ed))ans+=update(st,ed);return ans; }void dfs1(int x) {cout<<str[x-n]<<endl;vis[x-n]=true;for(int i=head[x];i!=-1;i=edge[i].next){int to=edge[i].to;int w=edge[i].w;if(w==0&&to!=st&&to!=ed&&to<=n&&to>x-n){dfs1(to+n);break;}} }void dfs2(int x) {vis[x-n]=true;for(int i=head[x];i!=-1;i=edge[i].next){int to=edge[i].to;int w=edge[i].w;if(w==0&&to!=st&&to!=ed&&to<=n&&to>x-n&&!vis[to]){dfs2(to+n);break;}}cout<<str[x-n]<<endl; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);init();scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){string s;cin>>s;mp[s]=i;str[i]=s;addedge(i,i+n,1,1);//拆點限流if(i==1||i==n)addedge(i,i+n,1,1); }addedge(st,1,2,0);addedge(n+n,ed,2,0);bool flag=false;while(m--){string a,b;cin>>a>>b;if(mp[a]>mp[b])swap(a,b);addedge(mp[a]+n,mp[b],1,0);if(mp[a]==1&&mp[b]==n)flag=true;}int ans=solve(st,ed);if(max_flow==2){printf("%d\n",ans-2);dfs1(1+n);dfs2(1+n);}else if(max_flow==1&&flag){puts("2");cout<<str[1]<<endl;cout<<str[n]<<endl;cout<<str[1]<<endl;}elseputs("No Solution!");return 0; }?
總結
以上是生活随笔為你收集整理的洛谷 - P2770 航空路线问题(最大费用最大流+路径打印)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷 - P4013 数字梯形问题(最大
- 下一篇: 洛谷 - P2754 [CTSC1999