HDU2485 Destroying the bus stations 最大流~Floyd+Dinic

Destroying the bus stations
Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2809    Accepted Submission(s): 933


Problem Description
Gabiluso is one of the greatest spies in his country. Now he’s trying to complete an “impossible” mission ----- to make it slow for the army of City Colugu to reach the airport. City Colugu has n bus stations and m roads. Each road connects two bus stations directly, and all roads are one way streets. In order to keep the air clean, the government bans all military vehicles. So the army must take buses to go to the airport. There may be more than one road between two bus stations. If a bus station is destroyed, all roads connecting that station will become no use. What’s Gabiluso needs to do is destroying some bus stations to make the army can’t get to the airport in k minutes. It takes exactly one minute for a bus to pass any road. All bus stations are numbered from 1 to n. The No.1 bus station is in the barrack and the No. n station is in the airport. The army always set out from the No. 1 station.
No.1 station and No. n station can’t be destroyed because of the heavy guard. Of course there is no road from No.1 station to No. n station.


Please help Gabiluso to calculate the minimum number of bus stations he must destroy to complete his mission.


Input
There are several test cases. Input ends with three zeros.

For each test case:

The first line contains 3 integers, n, m and k. (0< n <=50, 0< m<=4000, 0 < k < 1000)
Then m lines follows. Each line contains 2 integers, s and f, indicating that there is a road from station No. s to station No. f.


Output
For each test case, output the minimum number of stations Gabiluso must destroy.


Sample Input

5 7 3
1 3
3 4
4 5
1 2
2 5
1 4
4 5
0 0 0



Sample Output

2



Source
2008 Asia Regional Beijing

题意:
最少删除几个点,使得 1 到 n 的最短距离 >= k


显然 ,在图中 ,最短路 >= k 的点毫无意义 ,只有能够使得s->t的最短路 < k 的边才有意义
那跑一边Floyd ,如果dis[s][u]+dis[v][t] < k 表明(u,v)这条边可以使dis[s][t] < k (注意统计的是点数 不是边数 dis[s][u]+dis[v][t]不需要再+1)
保留这些边 ,其他全部删除 ,问题便转化为 最少删掉几个点 ,使s->t不联通

根据最大流最小割定理
当网络流中所有边权值为 1 ,使得s->t不联通 ,需要删除的边数就等于s->t的最大流
如果将图中每个点拆点 ,分为一个入点,一个出点,入点 到 出点 有一条权值为 1 的边 (s 和 t 拆点的权值为INF) 那删除 入点 到 出点 之间的边 ,就等价于删除掉这个点
所以 对Floyd处理后的图进行拆点 再跑一遍最大流


#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<time.h>
#include<math.h>
#include<list>
#include<cstring>
#include<fstream>
//#include<memory.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define INF 1000000007
#define pll pair<ll,ll>
#define pid pair<int,double>

const int N = 2*50 + 5;//点数
const int M = 4000*3 + 5;//边数*2(包括反向边)

int level[N];//标号 level[i]:s到i的最短距离

struct Edge{
    int to,c,next;
}edge[M];
int head[N];

pii edge_pii[M];

inline void add_edge(int k,int u,int v,int c){
    edge[k].to = v;
    edge[k].c = c;
    edge[k].next = head[u];
    head[u] = k;
}

bool bfs(int s,int t,int n){//标号 计算level
    deque<int>que;
    fill(level,level+n+1,-1);
    que.push_back(s);
    level[s] = 0;
    while(!que.empty()){
        int u = que.front();
        if(u == t){
            return true;
        }
        que.pop_front();
        for(int i = head[u];i!=-1;i = edge[i].next){
            if(edge[i].c > 0 && level[edge[i].to] == -1){
                level[edge[i].to] = level[u] + 1;
                que.push_back(edge[i].to);
            }
        }
    }
    return false;
}

int dfs(int u,int t,int maxf){//u:所在的点 t:汇点 maxf:能流到u的流量
    if(u == t){
        return maxf;
    }
    int sum = 0;
    for(int i = head[u];i!=-1;i = edge[i].next){
        const Edge&e = edge[i];
        if(e.c>0 && level[e.to]>level[u]){
            int f = dfs(e.to,t,min(maxf - sum,e.c));
            sum += f;
            edge[i].c -= f;
            edge[i^1].c += f;
            if(sum == maxf){//流量用完了
                return sum;
            }
        }
    }
    return sum;
}

int dinic(int s,int t,int n){//s:源点 t:汇点 n:点数
    int ans = 0;
    while(bfs(s,t,n)){
        ans += dfs(s,t,INF);
    }
    return ans;
}

int dis[N][N];

void floyd(int n){
    for(int k=1;k<=n;++k){
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
            }
        }
    }
}

int main()
{
    //freopen("/home/lu/Documents/r.txt","r",stdin);
    //freopen("/home/lu/Documents/w.txt","w",stdout);
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k),n){
        fill(head,head+2*n+1,-1);
        for(int i=1;i<=n;++i){
            fill(dis[i],dis[i]+n+1,INF);
            dis[i][i]=0;
        }
        for(int i=0;i<m;++i){
            int&u=edge_pii[i].first,&v=edge_pii[i].second;
            scanf("%d%d",&u,&v);
            dis[u][v]=1;
        }
        floyd(n);
        int num_e=0;
        for(int i=1;i<=n;++i){
            if(i==1||i==n){
                add_edge(num_e++,i,i+n,INF);
                add_edge(num_e++,n+i,i,0);
                continue;
            }
            add_edge(num_e++,i,i+n,1);
            add_edge(num_e++,i+n,i,0);
        }
        for(int i=0;i<m;++i){
            int&u=edge_pii[i].first,&v=edge_pii[i].second;
            if(dis[1][u]+dis[v][n]<k){//此处巨坑 因为需要统计点数而非边数 所以dis[1][u]+dis[v][n]+1是错的
                add_edge(num_e++,u+n,v,1);
                add_edge(num_e++,v,u+n,0);
            }
        }
        printf("%d\n",
               dinic(1,2*n,2*n));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值