题目大意:

给定一张航空图,图中顶点代表城市,边代表 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. fieldset ----- 不常用的HTML标签

    fieldset 元素可将表单内的相关元素分组. <fieldset> 标签将表单内容的一部分打包,生成一组相关表单的字段. 当一组表单元素放到 <fieldset> 标签内时 ...

  2. JavaScript的相关知识

      Oject.assign()   // Cloning an object var obj = { a: 1 }; var copy = Object.assign({}, obj); conso ...

  3. 【转】升级还是权谋?从USB PD 2.0到3.0

    原文出处 http://www.eetop.cn/blog/html/43/n-433743.html 如同iPhone的出现,才让智能机真正主导手机市场一样,Type-C口发布后,USB PD才正式 ...

  4. JS——缓慢动画封装

    在知道如何获取内嵌式和外链式的标签属性值之后,我们再次封装缓慢动画: 单个属性 <!DOCTYPE html> <html> <head lang="en&qu ...

  5. THREE.js代码备份——canvas - geometry - earth(球体贴纹理)

    <!DOCTYPE html> <html lang="en"> <head> <title>three.js canvas - g ...

  6. 【技术累积】【点】【java】【23】super以及重写重载

    重写和重载 重写是继承之后的Override 重载是同一个方法,有着不同的入参出参这样子: super 当需要在子类中调用父类的被重写方法时,要使用super关键字. 当然只要是调用父类的方法,都会用 ...

  7. JS 获得节点

    var ele = ev.parentNode; var elem_child = ele.childNodes; in elem_child) { //遍历子元素数组 if (elem_child[ ...

  8. Cesium学习笔记(五):3D 模型 (http://blog.csdn.net/umgsoil/article/details/74572877)

    Cesium支持3D模型,包括关键帧动画,皮肤的改变还有单个节点的选择等,Cesium还提供了了一个基于网络的工具,将COLLADA模型转换为glTF,方便和优化模型添加 还记得我们在实体添加的时候添 ...

  9. 爬虫文件存储-3:Redis

    前提条件: 安装并运行redis服务端程序,安装RedisPy库 说明:Redis 是 StrictRedis 的子类,它的主要功能是用于向后兼容旧版本库里的几个方法,官方推荐使用 StrictRed ...

  10. scrapy实例matplotlib脚本下载

    利用scrapy框架实现matplotlib实例脚本批量下载至本地并进行文件夹分类:话不多说上代码: 首先是爬虫代码: import scrapy from scrapy.linkextractors ...