uva 1324 运送超级计算机

【问题描述】

  宇宙中有n个星球,你的任务是用最短的时间把k个超级计算机从星球S运送到T,每个超级计算机需要一整艘飞船来运输。行星之间有m条双向隧道,每条隧道需要一天时间来通过,且不能有两艘飞船同时使用一条隧道。隧道不会连接两个不同的行星,且每一对行星之间最多只有一条通道。隧道不会连接两个相同的行星,且每一对行星之间最多只有一条隧道。

【输入格式】

  第一行包含5个正整数n,m,k,S,T(S!=T)。接下来的m行,每行包含两个不同的整数u和v,表示行星u和v之间有一条隧道。注意,隧道时双向的,但每一天只有一艘飞船能穿过一条隧道。另外,两艘飞船不能同时沿着相反的方向穿过同一个隧道。

【输出格式】

  输出一行,为最少需要的天数day。注意:所有的数据中,答案day不会超过100。

【输入样例】

【样例1】
 4 3 2 1 4
 1 2
 2 3
 3 4

【样例2】
 4 4 3 1 4
 1 2
 1 3
 3 4
 2 4

【输出样例】

【样例1】
 4

【样例2】
 3

【数据范围】

n <= 150,m <= 400, k <= 50

【来源】

uva 1324

这是一道比较复杂的最大流的题了。对于网络流我们首先想到的还是应该找源点和汇点,这里的汇点明显需要认为创造超级汇点(每天的终点都要指向汇点)。
对于这道题,我这里采取了一天一天加图的方法。(这样可以利用前面的直接加点后继续流就可以了)。
把每个点分成若干个点第i*n个点表示第n个点在第i天的对应点。然后每加一天多一层结点,加边就可以了。这里要注意每个点都可以走向同一个点的对应的下一天的点。
详细代码如下:

#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn=15005;
const int inf=20000005;

struct edge
{
    int u,v,cap,flow;
}b[405];
vector<edge>e;
vector<int>g[maxn];
int n,m,s,t,num,a[maxn],fa[maxn],q[maxn*10],cnt=-1,S,T,flow=0;

void add(int x,int y,int c)
{
    e.push_back((edge){x,y,c,0});
    g[x].push_back(++cnt);
    e.push_back((edge){y,x,0,0});
    g[y].push_back(++cnt);
}
void work(int tt)
{
    for(int i=1;i<=n;i++) add((tt-1)*n+i,tt*n+i,inf);
    for(int i=1;i<=m;i++)
    {
        add(b[i].u+(tt-1)*n,tt*n+b[i].v,1);
        add(b[i].v+(tt-1)*n,tt*n+b[i].u,1);
    }
    add(t+tt*n,T,inf);
}
int bfs()
{
    int root=0,frond=0;
    memset(fa,0,sizeof(fa));
    memset(a,0,sizeof(a));
    q[root++]=S;
    a[S]=inf;
    fa[S]=-1;
    while(root!=frond)
    {
        int i=q[frond++];
        int tt=g[i].size();
        for(int k=0;k<tt;k++)
        {
            int id=g[i][k],j=e[id].v;
            if(a[j]||e[id].flow>=e[id].cap) continue;
            a[j]=min(a[i],e[id].cap-e[id].flow);
            fa[j]=id;
            q[root++]=j;
            if(j==T) return a[T];
        }
    }
    return -1;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d%d%d%d",&n,&m,&num,&s,&t);
    for(int i=1;i<=m;i++) scanf("%d%d",&b[i].u,&b[i].v);
    S=0,T=n*100+1;
    add(S,s,inf);add(t,T,inf);
    int i=1;
    for(;i<=100;i++)
    {
        work(i);
        while(1)
        {
            int delt=bfs();
            if(delt==-1) break;
            flow+=delt;
            int id=fa[T];
            while(id!=-1)
            {
                e[id].flow+=delt;
                e[id^1].flow-=delt;
                id=fa[e[id].u];
            }
        }
        if(flow>=num) break;
    }
    printf("%d",i);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值