【题解】【网络流24题】航空路线问题 [P2770] [Loj6122]

传送门:航空路线问题 \([P2770]\) \([Loj6122]\)

【题目描述】

给出一张有向图,每个点(除了起点 \(1\))每条边都只能经过一次,求出从 \(1\) 到 \(n\) 在回到 \(1\) 的一条路径,使得经过的点个数最大,并输出路径。

【输入】

第一行两个整数 \(n,m\) 表示点数和边数。接下来 \(n\) 行字符串表示这 \(n\) 个点的名称(编号从 \(1\) 到 \(n\)),再接下来 \(m\) 行,每行两个字符串,表示这两个点之间有一条有向边(方向总是从编号小的点到编号大的点,但输入不一定保证左边的边号比右边大)。

【输出】

第一行为所能经过的最大节点数 \(ans\),接下来 \(ans+1\) 行输出途径节点名称。如果无解则输出 \(No\) \(Solution!\)。

【样例】

样例输入:
8 9
Vancouver
Yellowknife
Edmonton
Calgary
Winnipeg
Toronto
Montreal
Halifax
Vancouver Edmonton
Vancouver Calgary
Calgary Winnipeg
Winnipeg Toronto
Toronto Halifax
Montreal Halifax
Edmonton Montreal
Edmonton Yellowknife
Edmonton Calgary 样例输出:
7
Vancouver
Edmonton
Montreal
Halifax
Toronto
Winnipeg
Calgary
Vancouver

【数据范围】

\(100\%\) \(n \leqslant 100\)


【分析】

这是一道网络瘤题目。

那么,如何建模呢?

【建模】

俗话说得好啊:网络瘤,网络瘤,网络建模最毒瘤。

稍微一不注意踩到了坑就 \(GG\) 。

把题意转换一下,实际上是求从 \(1\) 到 \(n\) 的两条互不相交的路径。

限制条件是除起点、终点外的每条边、每个点只能经过一次,那么就可以进行拆点,把点可以经过的最大次数作为点内部的流量节点数作为点内部的费用,最后用 \(MCMF\) 求一个最大流最大花费。

求出的最大流就是所找到的路径数,如果它小于等于 \(1\),就说明找不到这样一条路径。

但有一种特殊情况需要特判:起点、终点只有一条边相连,这时候虽然只能找到一条路径,可 \(1\) 能直通 \(n\) 并直接回来,是合法的路径。

然后就是 \((sang)\) \((xin)\) \((bing)\) \((kuang)\) 的建图了:

首先把每个点拆为入点出点,并连一条流量可经过次数)为 \(1\),费用(节点数)为 \(1\) 的边,起点、终点要单独拆,流量设为 \(2\) 。

而对于输入的边 \((x,y)\),要把 \(x\) 的出点与 \(y\) 的入点相连(其实是个很简单的道理,一开始死活想不明白,而大佬们的题解基本都没讲,可能是觉得太简单了吧,我太蒻了。。。)。

【求答案】

答案分三种情况:

\((1).\) 当最大流等于 \(2\) 时,最大花费减 \(2\) 即为可经过的最大节点数,减 \(2\) 是因为起点、终点都经过了两次。

\((2).\) 当处于上述 \(1\) 直通 \(n\) 的情况时,答案为 \(2\),路径为:起点→终点→起点。

\((3).\) 其他情况均为无解。

另外,情况 \((1)\) 中输出路径时写两个 \(dfs\) 遍历满流边

第一次随便跑,记录下跑过的节点编号,要注意的是这时候只能跑出一条路,所以找到路后要立马 \(break\)。

第二次跳过这些节点找剩下那条路径,由于最大流所找到的路径数)最多为 \(2\),所以这里是否 \(break\) 都无所谓(可能会快一丢丢吧)。

【Code】

#include<algorithm>
#include<iostream>
#include<string>
#include<cstdio>
#include<queue>
#include<map>
#define LL long long
#define Re register int
using namespace std;
const int N=103,M=40000,inf=2e9;
int x,y,o=1,n,m,h,t,st,ed,flag,cyf[N],pan[N],pre[N],dis[N],head[N];LL maxcost,maxflow;
struct QAQ{int w,to,next,flow;}a[M<<1];queue<int>Q;string CH,ch[N];map<string,int>ip;
inline void add(Re x,Re y,Re z,Re w){a[++o].flow=z,a[o].w=w,a[o].to=y,a[o].next=head[x],head[x]=o;}
inline void add_(Re a,Re b,Re flow,Re w){add(a,b,flow,w),add(b,a,0,-w);}
inline int SPFA(Re st,Re ed){
for(Re i=0;i<=ed;++i)dis[i]=-inf,pan[i]=0;
Q.push(st),pan[st]=1,dis[st]=0,cyf[st]=inf;
while(!Q.empty()){
Re x=Q.front();Q.pop();pan[x]=0;
for(Re i=head[x],to;i;i=a[i].next)
if(a[i].flow&&dis[to=a[i].to]<dis[x]+a[i].w){//最长路
dis[to]=dis[x]+a[i].w,pre[to]=i;
cyf[to]=min(cyf[x],a[i].flow);//最小残余网络
if(!pan[to])pan[to]=1,Q.push(to);
}
}
return dis[ed]!=-inf;
}
inline void EK(Re st,Re ed){
while(SPFA(st,ed)){
Re x=ed;maxflow+=cyf[ed],maxcost+=(LL)cyf[ed]*dis[ed];
while(x!=st){
Re i=pre[x];
a[i].flow-=cyf[ed];
a[i^1].flow+=cyf[ed];
x=a[i^1].to;
}
}
}
inline void dfs1(Re x){
pan[x]=1;//记录一下第一次选的点,第二次就不选它们了
cout<<ch[x-n]<<endl;//第一次正序输出。记得减n
for(Re i=head[x],to;i;i=a[i].next)
if((to=a[i].to)<=n&&!a[i].flow){dfs1(to+n);break;}//出点x>n到入点to<=n,再从to的出点搜下去
}
inline void dfs2(Re x){
for(Re i=head[x],to;i;i=a[i].next)
if((to=a[i].to)<=n&&!a[i].flow&&!pan[to+n])dfs2(to+n);//出点x>n到入点to<=n,再从to的出点搜下去
cout<<ch[x-n]<<endl;//第二次倒序输出。记得减n
}
int main(){
cin>>n>>m;st=1,ed=n<<1;
for(Re i=1;i<=n;++i)cin>>ch[i],ip[ch[i]]=i;
for(Re i=2;i<n;++i)add_(i,n+i,1,1);//1~n表示入点,n+1~2n表示出点
add_(1,1+n,2,1),add_(n,n+n,2,1);//起点和中点可以经过两次
while(m--){
cin>>CH;x=ip[CH];
cin>>CH;y=ip[CH];
if(x>y)swap(x,y);
flag|=x==1&&y==n;
add_(x+n,y,1,0);//刚从x的出点出来,接下来连到y的入点
}
EK(st,ed);
if(maxflow==2)printf("%d\n",maxcost-2);//找到了两条路
else if(maxflow==1&&flag){//只有一条从1直通n的边
printf("2\n");
cout<<ch[1]<<endl<<ch[n]<<endl<<ch[1]<<endl;//这里要输出三个
return 0;
}
else return !printf("No Solution!\n");
for(Re i=1;i<=n+2;++i)pan[i+n]=0;
dfs1(1+n),dfs2(1+n);//根据边的残余网络来判断是否选了该边,所以从出点开始搜,这里害我调了一个多小时
}

【题解】【网络流24题】航空路线问题 [P2770] [Loj6122]的更多相关文章

  1. loj #6122. 「网络流 24 题」航空路线问题

    #6122. 「网络流 24 题」航空路线问题 题目描述 给定一张航空图,图中顶点代表城市,边代表两个城市间的直通航线.现要求找出一条满足下述限制条件的且途经城市最多的旅行路线. 从最西端城市出发,单 ...

  2. 【题解】【网络流24题】汽车加油行驶问题 [P4009] [Loj6223]

    [题解][网络流24题]汽车加油行驶问题 [P4009] [Loj6223] 传送门:汽车加油行驶问题 \([P4009]\) \([Loj6223]\) [题目描述] 给出一个 \(N \times ...

  3. [网络流24题]最长k可重区间集[题解]

    最长 \(k\) 可重区间集 题目大意 给定实心直线 \(L\) 上 \(n\) 个开区间组成的集合 \(I\) ,和一个正整数 \(k\) ,试设计一个算法,从开区间集合 \(I\) 中选取开区间集 ...

  4. 【线性规划与网络流 24题】已完成(3道题因为某些奇怪的原因被抛弃了QAQ)

    写在前面:SDOI2016 Round1滚粗后蒟蒻开始做网络流来自我拯救(2016-04-11再过几天就要考先修课,现在做网络流24题貌似没什么用←退役节奏) 做的题目将附上日期,见证我龟速刷题. 1 ...

  5. 【算法】【网络流24题】巨坑待填(成功TJ,有时间再填)

    ------------------------------------------------------------------------------------ 17/24 --------- ...

  6. 网络流基础&网络流24题

    网络最大流 dinic+当前弧优化. const int N=10007,M=100007,inf=1e9; int s,t,head[N],ver[M],edge[M],Next[M],tot=1, ...

  7. LOJ6000 - 「网络流 24 题」搭配飞行员

    原题链接 题意简述 求二分图的最大匹配. 题解 这里写的是匈牙利算法. 表示节点的当前匹配. 为真表示在这一轮匹配中,无法给节点一个新的匹配.所以如果为真就不用再dfs它了,直接continue就好. ...

  8. 【网络流24题】最长k可重线段集(费用流)

    [网络流24题]最长k可重线段集(费用流) 题面 Cogs的数据有问题 Loj 洛谷 题解 这道题和最长k可重区间集没有区别 只不过费用额外计算一下 但是,还是有一点要注意的地方 这里可以是一条垂直的 ...

  9. 【网络流24题】最长k可重区间集(费用流)

    [网络流24题]最长k可重区间集(费用流) 题面 Cogs Loj 洛谷 题解 首先注意一下 这道题目里面 在Cogs上直接做就行了 洛谷和Loj上需要判断数据合法,如果\(l>r\)就要交换\ ...

随机推荐

  1. Python Django Vue 项目创建

    环境安装忽略,可参考前面个篇幅介绍 1.创建项目 打开pycharm 终端,输入如下,创建项目 # 进入pycharm 项目目录下 cd pyWeb django-admin startproject ...

  2. fastadmin CMS等系列插件安装不成功的问题

    由于fastadmin开发者  没有做到权限优化问题,导致用户在linux服务器上lnmp环境下安装的fastadmin后台安装插件一直产生权限不足,安装不成功的问题, 再次给大家一个具体解决办法 对 ...

  3. 【MySQL】自增步长调整

    mysql> show variables like '%increment%'; +-----------------------------+-------+ | Variable_name ...

  4. Spring通过配置类加载实体bean

    以下4个java类都在都一个包下: 1.定义接口 public interface AA { void play(); } 2.定义实体bean //组件注解,表明该类是一个组件 @Component ...

  5. 是否忘记了向源中添加“#include "StdAfx.h"”?

    错误分析 此错误发生的原因是编译器在寻找预编译指示头文件(默认#include "stdafx.h")时,文件未预期结束.没有找到预编译指示信息的头文件"stdafx.h ...

  6. terminator

    terminator 能够实现linux 终端的分屏显示. 安装 sudo add-apt-repository ppa:gnome-terminator sudoapt-get update sud ...

  7. Java期末复习——主观题

    JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Runtime Envir ...

  8. 目标检测论文解读9——R-FCN

    背景 基于ResNet 101的Faster RCNN速度很慢,本文通过提出Position-sensitive score maps(位置敏感分值图)来给模型加速. 方法 首先分析一下,为什么基于R ...

  9. Java面试题:HashMap和HashTable的区别

    HashMap和HashTable的区别是面试时面试官经常问的问题,在回答的时候可以选择重点做回答,区别主要有下面几点:key和value的取值范围不同HashMap和HashTable都是基于哈希表 ...

  10. Peekaboo(2019年上海网络赛K题+圆上整点)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 你的位置在\(O(0,0)\),\(A\)的位置为\((x_1,y_1)\),\(B\)的位置为\((x_2,y_2)\),现在已知\(a=O ...