您的位置:首页 > 其它

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

2017-01-19 14:18 387 查看
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
;//标号 level[i]:s到i的最短距离

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

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();

147f3
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

;

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]
<k){//此处巨坑 因为需要统计点数而非边数 所以dis[1][u]+dis[v]
+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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU 图论 Floyd Dinic