HDU2485 Destroying the bus stations(最小割---点割)

Destroying the bus stations

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2319    Accepted Submission(s): 743

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

这题求的是最少去掉几个顶点,使得图的源点和汇点不连通(不可到达或用时大于K)。想想最小割的定义:最小割C(S,T)=最大流,如果图中每条边的流量都是1,那么最小割就变成了去掉最少的边,使得图的源点和汇点不连通。把这题中每个顶点拆分成两个顶点,中间用一条流量为1的边连接(u->(u+n))...这样,模型就满足最小割模型了。还有一个限制是路径长度大于k的路径可以不用考虑。这里只需先用spfa预处理,把每个顶点到汇点的最少花费算出,用于启发式寻找满足条件的增广流路,除点自身的边花费时间为0外,其他每条边的花费是1,当路径费用大于k的时候终止最大流过程即可。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int

const int MAXN = 1010;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边
int pre[MAXN];
int fromeS[MAXN],fromeT[MAXN];

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
captype maxFlow_sap(int sNode,int eNode, int n,int maxtime){//n是包括源点和汇点的总点个数,这个一定要注意
    memset(gap,0,sizeof(gap));
    memset(dis,0,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    memset(fromeS,-1,sizeof(fromeS));
    fromeS[sNode]=0;
    pre[sNode] = -1;
    gap[0]=n;
    captype ans=0;  //最大流
    int u=sNode ;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[i].cap-edg[i].flow){
                Min=edg[i].cap-edg[i].flow;
                inser=i;
            }
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
                edg[i].flow+=Min;
                edg[i^1].flow-=Min;  //可回流的边的流量
                //printf("<-%d ",edg[i].to);
            }
            ans+=Min;
            u=edg[inser^1].to;
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v , add ;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to; 

            //------------------寻找一条可满足条件的增广流------------------------
            add=0;
            if(u!=v-n/2) add=1; //如果从u-->v是正向流,且不是经过点自身的内部流,则需要花一个时间单位,如果是回流,说明回流的流量寻找其他可增流路
            if(edg[i].cap>0&&fromeS[u]+add+fromeT[v]>maxtime)
                continue;
            else if(edg[i].cap>0)
                fromeS[v]=fromeS[u]+add;//printf("(%d,%d,%d) ",u,v,add);
            //---------------------------------------------------------------------

            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag){
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next){
            v = edg[i].to;  add=0;
            if(u!=v-n/2) add=1;
            if(edg[i].cap>0&&fromeS[u]+add+fromeT[v]>maxtime)
                continue;
            else if(edg[i].cap>0)
                fromeS[v]=fromeS[u]+add;
            if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
                Mind=dis[edg[i].to];
                cur[u]=i;
            }
        }

        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;//如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
    }//printf("# %d ",fromeS[2]);
    return ans;
}
void spfa(int s,int t,int n){
    queue<int>q;
    int inq[MAXN]={0};
    for(int i=1; i<=n; i++)
        fromeT[i] = INF;
    fromeT[t]=0;
    q.push(t);
    while(!q.empty()){
        int u=q.front(); q.pop();
        inq[u]=0;
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to , add = 0;
            if(u!=v+n/2) add=1;
            if(edg[i].cap==0&&fromeT[edg[i].to]>fromeT[u]+add){//都取反向边
                fromeT[edg[i].to]=fromeT[u]+add;
                if(!inq[v])
                    inq[v]=1,q.push(v);
            }
        }
    }
}
int main(){
    int n,m,k;
    int u,v;
    while(scanf("%d%d%d",&n,&m,&k)>0){
        if(n==0&&m==0&&k==0)
            break;
        init();
        for(int i=1; i<=n; i++)
            addEdg(i,i+n,1);
        while(m--){
            scanf("%d%d",&u,&v);
            addEdg(u+n,v,1);
        }
        spfa(1+n,n,n*2);//printf("%d  ",fromeT[1+n]);
        int ans=maxFlow_sap(1+n , n , n*2, k);
        printf("%d\n",ans);
    }
}
时间: 2024-10-07 12:33:53

HDU2485 Destroying the bus stations(最小割---点割)的相关文章

hdu 2485 Destroying the bus stations 最小费用最大流

题意: 最少需要几个点才能使得有向图中1->n的距离大于k. 分析: 删除某一点的以后,与它相连的所有边都不存在了,相当于点的容量为1.但是在网络流中我们只能直接限制边的容量.所以需要拆点来完成对的点容量的限制.对于边i -> j,先建边i ->i',再建i'->j.i ->i'只能建一次,容量为1,费用为0.i'->j的容量是INF.此题中因为已经有源点,所以源点(1)不能限制容量. 1 #include<iostream> 2 #include<c

Destroying the bus stations

hdu2485:http://acm.hdu.edu.cn/showproblem.php?pid=2485 题意:给你一个图,让你删除其中的一些点,然后使得1到n的最小距离大于k,求删除的最小的点数. 题解:DFS枚举最短路径上的点. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #def

hdu 2485 Destroying the bus stations 迭代加深搜索

求最少去掉几个公交站使得从s到t的最短路径大于k. 迭代加深搜索. #include <cstdio> #include <cstring> #include <queue> using namespace std; #define maxn 60 #define maxm 50000 int n,m,K,cnt,up; int head[maxn],pre[maxn]; int road[maxn][maxn]; bool del[maxn]; queue<in

HDUOJ----2485 Destroying the bus stations

Destroying the bus stations Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2072    Accepted Submission(s): 647 Problem Description Gabiluso is one of the greatest spies in his country. Now he'

Destroying the bus stations (hdu 2485 网络流+最短路)

Destroying the bus stations Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2313    Accepted Submission(s): 739 Problem Description Gabiluso is one of the greatest spies in his country. Now he'

HDU 2485 Destroying the bus stations(费用流)

http://acm.hdu.edu.cn/showproblem.php?pid=2485 题意: 现在要从起点1到终点n,途中有多个车站,每经过一个车站为1时间,现在要在k时间内到达终点,问至少要破坏多少个车站. 思路: 把每个点拆分为两个点,容量为1,费用为0.之后相邻的车站连边,容量为INF,费用为1,表示经过一个车站需要1时间. 这样一来,跑一遍费用流计算出在费用不大于k的情况下的最大流,也就是最小割,即至少要破坏的车站数. 在网络中寻求关于f的最小费用增广路,就等价于在伴随网络中寻求

HDU 2485 Destroying the bus stations

2015 ACM / ICPC 北京站 热身赛 C题 #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<algorithm> using namespace std; const int INF=0x7FFFFFFF; const int maxn=50+10;//点的数量 int n,m,k; in

POJ2125 Destroying The Graph 二分图 + 最小点权覆盖 + 最小割

思路来源:http://blog.csdn.net/lenleaves/article/details/7873441 求最小点权覆盖,同样求一个最小割,但是要求出割去了那些边, 只要用最终的剩余网络进行一次遍历就可以了,比较简单. 建图:同样是一个二分图,左边的点代表去掉出边, 右边的点代表去掉入边(小心别弄混),左边去掉出边的点与源点相连, 容量为wi- . 然后更据给出的弧进行连线,权值为INF 使用很好理解的EK算法:(360MS) //#pragma comment(linker, "

scu - 3254 - Rain and Fgj(最小点权割)

题意:N个点.M条边(2 <= N <= 1000 , 0 <= M <= 10^5),每一个点有个权值W(0 <= W <= 10^5),现要去除一些点(不能去掉点0),使得结点 0 与结点 N - 1 不连通,求去掉的点的最小权值和. 题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=3254 -->>这是很明显的最小点权割.. 建图方案: 1)将全部点 i 拆成 i 和 i + N.i ->