luogu2754 星际转移问题 网络流
题目大意:地球与月球间有可容纳无限人的太空站,还有在太空站与星球间按周期行驶的、有固定容量的太空船,每一艘太空船从一个太空站驶往任一太空站耗时均为 1。地球上有一定数量的人,问所有人到月球最少需要多少天。
关键词:分层 最小费用最大流
最大流:把人群看作流。
分层:人们的最优选择会受到其位于哪一天的影响,因此我们关于时间将整个图分层。估计一下最多能用多少天,就分多少层。人们在太空站内可以呆着,因此每天的太空站要向下一天的太空站连容量∞费用1边。太空船运人,因此太空船前一站向下一天的后一站连容量∞费用1边。人类量固定,从S点向第一天的地球连容量为人数费用0边。任意时刻到达月球均可,从每天的月球向T连容量为无穷费用0边。
最小费用:这里的MCMF有些不同:费用不是单位费用,而是绝对费用;最小费用是每次SPFA所得路径的总费用的最大值,而不是和(否则同一天两群人坐船就被算成了两天)。
#include <cstdio>
#include <cstring>
#include <cassert>
#include <queue>
#include <vector>
using namespace std;
//#define test #define LOOP(i,n) for(int i=1; i<=n; i++)
#define S(station, day) station + (day - 1) * TotStation
#define R(x, t) (x - 1) % (t) + 1
#define INF 0x3f3f3f3f
const int MAX_SHIP = , MAX_STOP = , MAX_DAY = , MAX_NODE = MAX_STOP * MAX_DAY; int TotStation, TotShip, TotHuman;
int Cap[MAX_SHIP], Route[MAX_SHIP][MAX_STOP], StopCnt[MAX_STOP]; struct MCMF
{
struct Node;
struct Edge; struct Node
{
Edge *Head, *Prev;
int Dist, Id;
bool Inq;
}; struct Edge
{
int Cap, Cost, OrgCap;
Node *From, *To;
Edge *Next, *Rev;
}; Node _nodes[MAX_NODE];
vector<Edge*> _edges;
int _vCount = , _eCount = ;
Node *Start, *Sink;
int TotFlow, TotCost; void Init(int n, int sId, int tId)
{
_vCount = n;
_eCount = ;
Start = &_nodes[sId], Sink = &_nodes[tId];
TotFlow = TotCost = ;
} Edge *NewEdge()
{
if (_eCount < _edges.size())
return _edges[_eCount];
else
{
_edges.push_back(new Edge());
return _edges[_eCount++];
}
} Edge* AddEdge(Node *from, Node *to, int cap, int cost)
{
Edge *e = NewEdge();
e->From = from;
e->To = to;
e->OrgCap = e->Cap = cap;
e->Cost = cost;
e->Next = e->From->Head;
e->From->Head = e;
return e;
} void Build(int uId, int vId, int cap, int cost)
{
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
Edge *edge1 = AddEdge(u, v, cap, cost), *edge2 = AddEdge(v, u, , -cost);
edge1->Rev = edge2;
edge2->Rev = edge1;
} bool SPFA()
{
queue<Node*> q;
LOOP(i, _vCount)
{
_nodes[i].Prev = NULL;
_nodes[i].Dist = INF;
_nodes[i].Inq = false;
}
Start->Dist = ;
q.push(Start);
while (!q.empty())
{
Node *u = q.front();
q.pop();
//printf("SPFA %d Dist %d\n", u->Id, u->Dist);
u->Inq = false;
for (Edge *e = u->Head; e; e = e->Next)
{
if (e->Cap && u->Dist + e->Cost < e->To->Dist)
{
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, curCost = ;
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;
curCost += e->Cost;
}
TotCost = max(TotCost, curCost);
}
}
}g; int Proceed(int totDay)
{
int sId = TotStation*totDay + , tId = TotStation*totDay + ;
g.Init(tId, sId, tId);
g.Build(sId, , TotHuman, );
for (int i = ; i < sId; i += TotStation)
g.Build(i, tId, INF, );
LOOP(station, TotStation)
LOOP(day, totDay - )
g.Build(S(station, day), S(station, day + ), INF, );
LOOP(ship, TotShip)
LOOP(day, totDay - )
g.Build(S(Route[ship][R(day, StopCnt[ship])], day), S(Route[ship][R(day + , StopCnt[ship])], day + ), Cap[ship], );
g.Proceed();
if (g.TotFlow < TotHuman)
return ;
return g.TotCost;
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
scanf("%d%d%d", &TotStation, &TotShip, &TotHuman);
TotStation += ;
LOOP(i, TotShip)
{
scanf("%d%d", i + Cap, i + StopCnt);
LOOP(j, StopCnt[i])
{
scanf("%d", &Route[i][j]);
Route[i][j] += ;
}
}
printf("%d\n", Proceed(MAX_DAY));
return ;
}
注意:
1.要让包括星球在内的太空站的编号从1开始,否则容易晕。
2.最大值不要卡着边设。
luogu2754 星际转移问题 网络流的更多相关文章
- luogu2754 星际转移问题
源向地球连 月球向汇连 每一天往下一天连 飞船上一天与这一天连 枚举答案 #include <iostream> #include <cstring> #include < ...
- [CTSC1999][网络流24题] 星际转移
36. [CTSC1999][网络流24题] 星际转移 ★★★☆ 输入文件:home.in 输出文件:home.out 简单对比时间限制:1 s 内存限制:128 MB «问题描述: ...
- 线性规划与网络流24题●09方格取数问题&13星际转移问题
●(做codevs1908时,发现测试数据也涵盖了1907,想要一并做了,但因为“技术”不佳,搞了一上午) ●09方格取数问题(codevs1907 方格取数3) 想了半天,也没成功建好图: 无奈下 ...
- 【BZOJ3993】星际战争(网络流,二分答案)
[BZOJ3993]星际战争(网络流,二分答案) 题面 Description 3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战.在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团 ...
- Luogu 2469 [SDOI2010]星际竞速 / HYSBZ 1927 [Sdoi2010]星际竞速 (网络流,最小费用流)
Luogu 2469 [SDOI2010]星际竞速 / HYSBZ 1927 [Sdoi2010]星际竞速 (网络流,最小费用流) Description 10年一度的银河系赛车大赛又要开始了.作为全 ...
- Luogu P2754 星际转移问题
Luogu P2754 星际转移问题 思路 首先,对于地球能否到达月球的问题,考虑使用并查集维护. 对于每艘飞船能够到达的站点,放进一个集合里,若两艘飞船的集合有交集,那么就合并两个集合,最后只要地球 ...
- 网络流24题之星际转移问题(洛谷P2754)
洛谷 P2754 题目背景 none! 题目描述 由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,21 ...
- 【网络流24题】No. 13 星际转移问题 (网络判定 最大流)
[题意] 由于人类对自然资源的消耗, 人们意识到大约在 2300 年之后, 地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民. 令人意想不到的是, 2177 年冬由于未知的原因, 地球 ...
- [CTSC1999]【网络流24题】星际转移
Description 由于人类对自然资源的消耗,人们意识到大约在2300 年之后,地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,2177 年冬由于未知的原因,地 ...
随机推荐
- 自己写的_top、_parent以及对iframe和frameset的理解
iframe可以写在<body>标签里,如<body><iframe src="xxx" name="xxx" style=&q ...
- ViewPager PagerAdapter 的使用
1: 目的,实现全屏滑动的效果 2:类似于BaseAdapter public class MyPagerAdapter extends PagerAdapter { private Context ...
- 如何通过WallpaperManager(壁纸管理器)设置与修改壁纸?
WallpaperManager(壁纸管理器),是手机壁纸相关的一个API的相关类.其设置壁纸常有如下三种方法可调用: - setBitmap(Bitmap bitmap):将壁纸设置为bitmap所 ...
- Linux 与 Windows 文件互传(VMWare)
虚拟机无桌面的Linux 与 物理机Windows 文件互传有很多种方法,现在先说一种通过共享文件夹的形式,其他方法后续再补充 1. 背景 1) 虚拟机系统:VMWare无桌面的 ...
- oracle从入门到精通复习笔记
为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载:点我下载 描述一个表用 desc employees过滤重复的部门 select distinct department_id from e ...
- halcon 模板匹配 -- 转化 vector_angle_to_rigid
********************************模板匹配 ********************create_shape_model创建模板,这个函数有许多参数,其中金字塔的级数由N ...
- Verification之PSL之use
1 Where can PSL be used? • Documentation – Requirements – RTL Designs • Controllers – Memories, FIFO ...
- OpenCV边缘检测的详细参数调节
1. findCountours 转载于http://blog.sina.com.cn/s/blog_7155fb1a0101a90h.html findContours函数,这个函数的原型为: &l ...
- OpenCV的AdaptiveThreshold函数
摘自于OpenCV Doc2.410,opencv2refman文档. 1.函数原型 adaptiveThreshold //Applies an adaptive threshold to an a ...
- C# 检测字符串是否为数字
long n; 1. ], ].All(char.IsDigit); //识别空字符时候 会认为是数字 string str0 = ""; string str1 = " ...