hdoj 2485 Destroying the bus stations 【最小割 + 最短路】

来源:互联网 发布:软件行业 职业岗位 编辑:程序博客网 时间:2024/04/29 13:54

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 31 33 44 51 22 51 44 50 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][N] <= 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 10000000using 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][N] <= 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;}


0 0