hdoj 2485 Destroying the bus stations 【最小割 + 最短路】
2015-07-31 00:03
375 查看
Destroying the bus stations
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2407 Accepted Submission(s): 779
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
题意:给你N个车站和M条单向路径,经过每条路径耗时1分钟(路径可能重复)。现在敌军从1到N通过这些车站增兵, 问你最少破坏多少个车站 才能使增兵时间至少为K+1。
首先会想到最小割,但这破坏的是点。。。 想当然,我们可以拆点成边,建立最小割模型求解。
思路:首先Floyd预处理最短路,然后拆点i 为 i 和 i + N并建边,因为1和N两点不能破坏所以边权为INF,其余点边权为1。对M条边中的 任意边<u, v>若有 Map[1][u] + Map[u][v] + Map[v]
<= K 则建边 u + N - > v 边权为1。最后建立超级源点0连接1边权为INF,点2*N连接超级汇点2*N+1边权为INF。 接下来就是跑一遍0->2*N+1的最大流(也就是求最小割)。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define MAXN 200 #define MAXM 400000+100 #define INF 10000000 using namespace std; int Map[60][60]; struct Edge { int from, to, cap, flow, next; }; Edge edge[MAXM]; int head[MAXN], edgenum, cur[MAXN]; int dist[MAXN]; bool vis[MAXN]; int a[4000+10], b[4000+10];//存储边的信息 int N, M, K; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void getMap() { for(int i = 1; i <= N; i++) { for(int j = 1; j <= N; j++) Map[i][j] = i==j ? 0 : INF; } for(int i = 0; i < M; i++) scanf("%d%d", &a[i], &b[i]), Map[a[i]][b[i]] = 1; } void Floyd() { for(int k = 1; k <= N; k++) { for(int i = 1; i <= N; i++) { if(Map[i][k] == INF) continue; for(int j = 1; j <= N; j++) { if(Map[k][j] == INF) continue; Map[i][j] = min(Map[i][j], Map[i][k] + Map[k][j]); } } } } void addEdge(int u, int v, int w) { Edge E1 = {u, v, w, 0, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } void getEdge() { //建立超级源点0,超级汇点2*N+1 for(int i = 1; i <= N; i++) { if(i == 1 || i == N)//拆点建边 addEdge(i, i + N, INF);//起点终点不能断 else addEdge(i, i + N, 1);//建立符合最小割的模型 } //对于在小于或等于K的1->N路径上的边<u, v>建边u+N -> v for(int i = 0; i < M; i++) { int u = a[i]; int v = b[i]; if(Map[1][u] + Map[u][v] + Map[v] <= K) addEdge(u + N, v, 1); } //超级源点 连1 权值 为INF addEdge(0, 1, INF); //2*N 连超级汇点 权值为INF addEdge(2*N, 2*N+1, INF); } bool BFS(int start, int end) { queue<int> Q; memset(dist, -1, sizeof(dist)); memset(vis, false, sizeof(vis)); vis[start] = true; dist[start] = 0; Q.push(start); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(!vis[E.to] && E.cap > E.flow) { vis[E.to] = true; dist[E.to] = dist[u] + 1; if(E.to == end) return true; Q.push(E.to); } } } return false; } int DFS(int x, int a, int end) { if(x == end || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next) { Edge &E = edge[i]; if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(E.cap-E.flow, a), end)) > 0) { E.flow += f; edge[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int start, int end) { int flow = 0; while(BFS(start, end)) { memcpy(cur, head, sizeof(head)); flow += DFS(start, INF, end); } return flow; } int main() { while(scanf("%d%d%d", &N, &M, &K), N||M||K) { //memset(Map, INF, sizeof(map)); getMap(); Floyd(); init(); getEdge(); printf("%d\n", Maxflow(0, 2*N+1)); } return 0; }
相关文章推荐
- 从C++到objective-c
- hdu5336 XYZ and Drops (模拟+vector删除第i个元素)
- 关于.NET C#调用Sqlite的总结一
- 如何在 Linux 上安装设备驱动程序
- 简单理解Python中的装饰器
- 将Python代码嵌入C++程序进行编写的实例
- 如何使用纯PHP实现定时器任务(Timer)
- PHP内核探索:哈希表碰撞攻击原理
- 如何把php5.3版本升级到php5.4或者php5.5
- PHP查看当前变量类型的方法
- PHP 前加at符合@的作用解析
- PHP代码实现爬虫记录――超管用
- PHP中filter函数校验数据的方法详解
- 详解Grunt插件之LiveReload实现页面自动刷新(两种方案)
- php自定义类fsocket模拟post或get请求的方法
- 如何使用Gitblog和Markdown建自己的博客
- php使用Imagick生成图片的方法
- 使用Appcan客户端自动更新PHP版本号(全)
- 初识通用数据库操作类——前端easyui-datagrid,form(php)
- php给图片加文字水印