您的位置:首页 > 其它

【poj1895】Bring Them There 分层图最大流

2016-03-03 13:01 211 查看

Description

By the year 3141, the human civilization has spread all over the galaxy. The special hypertunnels are used to travel from one star system to another. To use the hypertunnel, you fly to a special location near the source star using your spaceship, activate the hyperjumper, fly through the hypertunnel, get out near your destination star and fly to the planet you need. The whole process takes exactly one day. A small drawback of the system is that for each tunnel every day only one spaceship can travel using this tunnel.

You are working in the transportation department of the “Intergalaxy Business Machines” company. This morning your boss has assigned a new task to you. To run the programming contest IBM needs to deliver K supercomputers from Earth where the company headquarters are located to the planet Eisiem. Since supercomputers are very large, one needs the whole spaceship to carry each supercomputer. You are asked to find a plan to deliver the supercomputers that takes as few days as possible. Since IBM is a very powerful corporation, you may assume that any time you need some tunnel for hyperjump, it is at your service. However, you still can use each tunnel only once a day.

Input

The first line of input contains N — the number of star systems in the galaxy, M — the number of tunnels, K — the number of supercomputers to be delivered, S — the number of the solar system (the system where planet Earth is) and T — the number of the star system where planet Eisiem is (2 <= N <= 50, 1 <= M <= 200, 1 <= K <= 50, 1 <= S, T <= N , S != T ).

Next M lines contain two different integer numbers each and describe tunnels. For each tunnel the numbers of star systems that it connects are given. The tunnel can be traveled in both directions, but remember that each day only one ship can travel through it, in particular, two ships cannot simultaneously travel through the same tunnel in opposite directions. No tunnel connects a star to itself and any two stars are connected by at most one tunnel.

Output

On the first line of output print L — the fewest number of days needed to deliver K supercomputers from star system S to star system T using hypertunnels. Next L lines must describe the process. Each line must start with Ci — the number of ships that travel from one system to another this day. Ci pairs of integer numbers must follow, pair A, B means that the ship number A travels from its current star system to star system B. It is guaranteed that there is a way to travel from star system S to star system T .

Sample Input

6 7 4 1 6
1 2
2 3
3 5
5 6
1 4
4 6
4 3


Sample Output

4
2 1 2 2 4
3 1 3 2 6 3 4
3 1 5 3 6 4 4
2 1 6 4 6


Source

Northeastern Europe 2003

n个点,m条边,指定起点终点,k个飞船,每天每条边上只能走一个飞船,每个飞船每天只能走一条边,问k个飞船到终点最少要几天,还要输出方案。

以为是二分,结果发现是动态加点的分层图…好像差不多

每次新加一层点,连有向边<ui,ui+1>,对于原图存在的边<u,v>,连<ui,vi+1>,<vi,ui+1>,然后源点s连第一层起点,每层的终点连汇点e。

然后每次新加一层在残量网络上加就可以了,不需要清空全图重新跑

输出方案,从起点dfsk次走有流量的边,代表k个飞船的路径。若飞船在原地呆了一天则不计入答案,若某条路在同一天被方向相反的两个飞船走了,则可以交换这俩飞船的路径

这题难在输出路径…………

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF = 1000000010;
const int SZ = 100010;

int s,e;

int head[SZ],nxt[SZ],tot = 1;

struct edge{
int t,d;
}l[SZ];

void build(int f,int t,int d)
{
l[++ tot].d = d;
l[tot].t = t;
nxt[tot] = head[f];
head[f] = tot;
}

void insert(int f,int t,int d)
{
build(f,t,d); build(t,f,0);
}

int deep[SZ];
queue<int> q;

bool bfs()
{
while(q.size()) q.pop();
memset(deep,0,sizeof(deep));
deep[s] = 1;
q.push(s);
while(q.size())
{
int f = q.front(); q.pop();
for(int i = head[f];i;i = nxt[i])
{
int v = l[i].t;
if(!deep[v] && l[i].d)
{
deep[v] = deep[f] + 1;
q.push(v);
if(v == e) return true;
}
}
}
return false;
}

int dfs(int u,int flow)
{
if(u == e || flow == 0) return flow;
int rest = flow;
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(deep[v] == deep[u] + 1 && l[i].d)
{
int f = dfs(v,min(rest,l[i].d));
if(f > 0)
{
l[i].d -= f;
l[i ^ 1].d += f;
rest -= f;
if(rest == 0) break;
}
else deep[v] = 0;
}
}
if(flow - rest == 0) deep[u] = 0;
return flow - rest;
}

int dinic()
{
int ans = 0;
while(bfs())
{
int tmp = dfs(s,INF);
if(!tmp) break;
ans += tmp;
}
return ans;
}

int ff[SZ],tt[SZ];
int n,m,k,S,E;

int days[10010],id[10010][55],to[10010][55];
//第i天有几个,第i天第j个的的编号/到的点
void find_ans(int u,int num,int d) //当前点,第几个,第几天
{
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(l[i ^ 1].d)
{
l[i].d ++;
l[i ^ 1].d --;
if(v == e) break;
if(v == u + n)
find_ans(v,num,d + 1);
else
{
days[d] ++;
id[d][days[d]] = num;
to[d][days[d]] = (v - 1) % n + 1;
find_ans(v,num,d + 1);
}
break;
}
}
}

int main()
{
scanf("%d%d%d%d%d",&n,&m,&k,&S,&E);
for(int i = 1;i <= m;i ++)
{
scanf("%d%d",&ff[i],&tt[i]);
}

s = 0,e = 20000;

insert(s,S,k); insert(E,e,INF);

int ans = 0,tot = 0;

while(233)
{
tot += dinic();
if(tot == k) break;
for(int i = 1;i <= m;i ++)
{
insert(ff[i] + n * ans,tt[i] + n * (ans + 1),1);
insert(tt[i] + n * ans,ff[i] + n * (ans + 1),1);
}
for(int i = 1;i <= n;i ++)
{
insert(i + n * ans,i + n * (ans + 1),INF);
}
insert(E + n * (ans + 1),e,INF);
ans ++;
}

printf("%d\n",ans);

for(int i = 1;i <= k;i ++)
find_ans(s,i,0);

for(int i = 1;i <= ans;i ++)
{
printf("%d ",days[i]);
for(int j = 1;j <= days[i];j ++)
printf("%d %d ",id[i][j],to[i][j]);
puts("");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: