题目大意:

给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
(2)除起点城市外,任何城市只能访问 1 次。

关键字:网络流 方向等效转换 拆点 不交叉路径 特判

网络流:1个人旅行的过程可以看作以流量为1流动的过程。

方向等效转化:本问题可以看作两个人同时从最西的城市走向最东的城市,每个人占有1个流量,总流量为2。

拆点:题中说每个城市只经过一次,因此把一个城市看作容量为1的边,如果西东两个城市之间有航线,则把西城to节点连东城from节点,容量为1。为保证总流量为2,最西城边容量和最东城容量为2。

不交叉路径:流量为1,即可保证路径不交叉

特判:如果最西城与最东城有航线,则边的容量为2。

#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <cassert>
#include <map>
#include <string>
#include <iostream>
using namespace std; //#define test
#define INF 0x3f3f3f3f
#define LOOP(i,n) for(int i=1; i<=n; i++)
const int MAX_CITY = , MAX_EDGE = MAX_CITY*MAX_CITY + MAX_CITY * , MAX_NODE = MAX_CITY * ;
map<string, int> loc;
string Cities[MAX_CITY];
bool Vis[MAX_CITY];
int TotCity, TotLine; struct MCMF
{
struct Node;
struct Edge; struct Node
{
int Id;
Edge *Head, *Prev;
int Dist;
bool Inq; void Init()
{
Prev = NULL;
Dist = INF;
Inq = false;
}
}; struct Edge
{
int Cap, Cost;
Node *From, *To;
Edge *Next, *Rev;
Edge(int cap, int cost, Node *from, Node *to, Edge *next) :Cap(cap), Cost(cost), From(from), To(to), Next(next){}
}; Node _nodes[MAX_NODE];
Edge *_edges[MAX_EDGE];
int _vCount = , _eCount = ;
Node *Start, *Sink;
int TotFlow, TotCost; void Reset(int n, int sId, int tId)
{
_vCount = n;
_eCount = ;
Start = &_nodes[sId], Sink = &_nodes[tId];
TotFlow = TotCost = ;
} Edge* AddEdge(Node *from, Node *to, int cap, int cost)
{
Edge *cur = _edges[++_eCount] = new Edge(cap, cost, from, to, from->Head);
from->Head = cur;
return cur;
} void Build(int uId, int vId, int cap, int cost)
{
Node *u = &_nodes[uId], *v = &_nodes[vId];
u->Id = uId;
v->Id = vId;
Edge *edge1 = AddEdge(u, v, cap, cost);
Edge *edge2 = AddEdge(v, u, , -cost);//遗忘点*2:-cost
edge1->Rev = edge2;
edge2->Rev = edge1;
} bool SPFA()
{
queue<Node*> q;
for (int i = ; i <= _vCount; i++)
_nodes[i].Init();
Start->Dist = ;
q.push(Start);
while (!q.empty())
{
Node *u = q.front();
q.pop();
u->Inq = false;//易忘点
for (Edge *e = u->Head; e; e = e->Next)
{
if (e->Cap && u->Dist + e->Cost < e->To->Dist)//易忘点*2:e->Cap
{
e->To->Dist = u->Dist + e->Cost;
e->To->Prev = e;
if (!e->To->Inq)
{
e->To->Inq = true;
q.push(e->To);
}
}
}
}
return Sink->Prev;
} void Proceed()
{
while (SPFA())
{
assert(Sink->Dist != INF);
int minFlow = INF;
for (Edge *e = Sink->Prev; e; e = e->From->Prev)
minFlow = min(minFlow, e->Cap);
TotFlow += minFlow;
for (Edge *e = Sink->Prev; e; e = e->From->Prev)
{
e->Cap -= minFlow;
e->Rev->Cap += minFlow;
TotCost += minFlow * e->Cost;
#ifdef test
printf("%d-%d Cost %d restCap %d\n", e->From->Id, e->To->Id, e->Cost*minFlow, e->Cap);
#endif
}
#ifdef test
printf("TotFlow %d TotCost %d\n", TotFlow, TotCost);
#endif
}
} int GetFlow()
{
return TotFlow;
} int GetCost()
{
return TotCost;
}
}g; void print1()
{
MCMF::Node *cur = + g._nodes;
while (cur->Id != TotCity)
{
Vis[cur->Id] = true;
cout << Cities[cur->Id] << endl;
cur = cur->Id + TotCity + g._nodes;
for (MCMF::Edge *e = cur->Head; e; e = e->Next)
{
if (!e->Cap && !Vis[e->To->Id] && e->To->Id > cur->Id-TotCity)
{
cur = e->To;
break;
}
}
}
} void print2(int id)
{
if (id == TotCity)
{
cout << Cities[id] << endl;
return;
}
Vis[id] = true;
MCMF::Node *cur = id + TotCity + g._nodes;
for (MCMF::Edge *e = cur->Head; e; e = e->Next)
{
if (!e->Cap && !Vis[e->To->Id] && e->To->Id > cur->Id - TotCity)
{
print2(e->To->Id);
break;
}
}
cout << Cities[id] << endl;
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
int sId, tId;
string s1, s2;
scanf("%d%d", &TotCity, &TotLine);
sId = ;
tId = TotCity * ;
g.Reset(tId, sId, tId);
LOOP(city, TotCity)
{
cin >> Cities[city];
loc.insert(pair<string, int>(Cities[city], city));
if (city == || city == TotCity)
g.Build(city, city + TotCity, , -);
else
g.Build(city, city + TotCity, , -);
}
LOOP(line, TotLine)
{
cin >> s1 >> s2;
int p1 = loc[s1], p2 = loc[s2];
if (p2 < p1)
swap(p1, p2);
if (p1 == && p2 == TotCity)
g.Build(p1+TotCity, p2, , );
else
g.Build(p1+TotCity, p2, , );
}
g.Proceed();
if (g.TotFlow<)
{
cout << "No Solution!" << endl;
return ;
}
printf("%d\n", -g.TotCost-);
LOOP(v, g._vCount)
g._nodes[v].Inq = false;
print1();
print2();
return ;
}

luogu2770 航空路线问题 网络流的更多相关文章

  1. luogu2770 航空路线问题

    前置技能:HDU3376 Matrix Again 所以看到这个题,我们也会想着用最大费用最大流解决,因为从起点飞到终点再飞回来,就等于从起点飞两次到终点且这两次飞行除了起点终点之外没有访问超过一次的 ...

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

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

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

    [题解][网络流24题]航空路线问题 [P2770] [Loj6122] 传送门:航空路线问题 \([P2770]\) \([Loj6122]\) [题目描述] 给出一张有向图,每个点(除了起点 \( ...

  4. JS前端三维地球渲染——中国各城市航空路线展示

    前言 我还从来没有写过有关纯JS的文章(上次的矢量瓦片展示除外,相对较简单.),自己也学习过JS.CSS等前端知识,了解JQuery.React等框架,但是自己艺术天分实在不过关,不太喜欢前端设计,比 ...

  5. 网络流 P2770 航空路线问题

    #include <cstdio> #include <cstdlib> #include <map> #include <queue> #includ ...

  6. 【刷题】LOJ 6122 「网络流 24 题」航空路线问题

    题目描述 给定一张航空图,图中顶点代表城市,边代表两个城市间的直通航线.现要求找出一条满足下述限制条件的且途经城市最多的旅行路线. 从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向 ...

  7. 【网络流24题】No.11(航空路线问题 最长不相交路径 最大费用流)

    [题意] 给定一张航空图, 图中顶点代表城市, 边代表 2 城市间的直通航线. 现要求找出一条满足下述限制条件的且途经城市最多的旅行路线.(1) 从最西端城市出发,单向从西向东途经若干城市到达最东端城 ...

  8. 【PowerOJ1746&网络流24题】航空路线问题(费用流)

    题意: 思路: [问题分析] 求最长两条不相交路径,用最大费用最大流解决. [建模方法] 把第i个城市拆分成两个顶点<i.a>,<i.b>. 1.对于每个城市i,连接(< ...

  9. LG2770/LOJ6122 航空路线问题 费用流 网络流24题

    问题描述 LG2770 LOG6122 题解 教训:关掉流同步之后就不要用其他输入输出方式了. 拆点. 两个拆点之间连\((1,1)\),其他连\((1,0)\) \(\mathrm{Code}\) ...

随机推荐

  1. 【转】Java 集合系列01之 总体框架

    Java集合是java提供的工具包,包含了常用的数据结构:集合.链表.队列.栈.数组.映射等.Java集合工具包位置是java.util.*Java集合主要可以划分为4个部分:List列表.Set集合 ...

  2. Less文件的建立

    1.打开DreamWeaver 2.选择 新建 Less       文件名为.less,保存于Less文件夹中 3.声明文档头:@charset "utf-8"; 4.将Less ...

  3. checkbox与文字混排无法对齐到一行的解决办法

    直接上代码: <span><input style="vertical-align:middle" type="checkbox" name= ...

  4. 移动web——bootstrap模板

    基本概念 1.bootstrap就是在媒体查询技术出现以后才开始出现的 2.此技术使响应式开发变得十分轻松,最大特点就是栅格系统(什么设备上如何显示)以及响应式工具(是否可见) 基本模板 <!D ...

  5. CSS——滑动门

    在背景图片中可以对图片进行圆角设置,但是这样是写死的.如下图: 情况分析:如果我们li标签中的文字变少了或者变多了,我们就需要重新定义背景图片.所以我们使用滑动门技术.它将图片特殊地方进行分割.宽度利 ...

  6. php入门学习笔记

    学习笔记[6.5-6.13] 1.常用命令 打开数据库格式: mysql -h主机地址 -u用户名 -p 重启nginx:sudo /etc/init.d/nginx restart或者service ...

  7. php判断form数据是否为POST而来,判断数据提交方式

    //判断form数据是否为POST而来,判断数据提交方式 if ($_SERVER['REQUEST_METHOD'] != 'POST') { // 非 POST 来路,做警告或你想做的事 retu ...

  8. pycharm之gitignore设置

    首先检查pycharm是否安装了ignore插件 项目目录如图: 选中项目automationTest名称,右击-->New-->查看是否有ignore file选项,如果有表示Pycah ...

  9. 文件上传原理--FileReader

    单个文件:<div> <input value="上传" type="file" id="photos_upload"&g ...

  10. 20190625_mysql5.7查看及其解锁_被锁的表

    [root@localhost ~]# mysql -u myroot -pEnter password: mysql> show OPEN TABLES where In_use > 0 ...