HDU5294 Tricks Device(最大流+SPFA) 2015 Multi-University Training Contest 1

来源:互联网 发布:井泵电机数据 编辑:程序博客网 时间:2024/05/21 06:49

Tricks Device

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 389    Accepted Submission(s): 100


Problem Description
Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang.
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.
 

Input
There are multiple test cases. Please process till EOF.
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i.
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.
 

Output
Output two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.
 

Sample Input
8 91 2 22 3 22 4 13 5 34 5 45 8 11 6 26 7 57 8 1
 

Sample Output
2 6
 

Source
2015 Multi-University Training Contest 1
 

Recommend
We have carefully selected several similar problems for you:  5299 5298 5297 5296 5295 
题意:给一个无向图N个点M条边,每条边都有一个时间花费,Innocent Wu只有用最短的时间去追 Dumb Zhang才能追上,但 Dumb Zhang不想让他追上,他可以断开任意边,问至少要断几条边,得答案1,答案2=最多能让他断多少路使得WU仍能追上zhang。
解题:用SPFA求出从N到所有点的最短路,和到所有点最短路上最少经过的边数numk[],这样可以得到答案2=M-numk[1]。接下来就用最大流来做,关键在找增广流时要添加一个满足到达N点时是最短路。
#include<stdio.h>#include<string.h>#include<queue>#include<vector>#include<algorithm>using namespace std;#define captype intconst int MAXN = 2010;   //点的总数const int MAXM = 400010;    //边的总数const int INF = 1<<30;struct EDG{    int to,next;    captype cap,flow;    int d;} 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 D[MAXN], vist[MAXN], mindis;void init(){    eid=0;    memset(head,-1,sizeof(head));}//有向边 三个参数,无向边4个参数void addEdg(int u,int v,int d,captype rc=0){    edg[eid].to=v; edg[eid].next=head[u];  edg[eid].d=d;    edg[eid].cap=1; edg[eid].flow=0; head[u]=eid++;    edg[eid].to=u; edg[eid].next=head[v];  edg[eid].d=INF;    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;}captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意    memset(gap,0,sizeof(gap));    memset(dis,0,sizeof(dis));    memcpy(cur,head,sizeof(head));    memset(vist,-1,sizeof(vist));    pre[sNode] = -1;    gap[0]=n;    captype ans=0;  //最大流    vist[sNode]=0;    int u=sNode ,i ;    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点        if(u==eNode){   //找到一条可增流的路            captype Min=INF ;            int inser;            for( 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( i=pre[u]; i!=-1; i=pre[edg[i^1].to]){                edg[i].flow+=Min;                edg[i^1].flow-=Min;  //可回流的边的流量            }            ans+=Min;            u=edg[inser^1].to;            continue;        }        bool flag = false;  //判断能否从u点出发可往相邻点流        int v;        for( i=cur[u]; i!=-1; i=edg[i].next){            v=edg[i].to;            if(edg[i].cap>0&&vist[u]+edg[i].d+D[v]!=mindis)//如果是正流,则必须保证是最短的一条路,如果是逆流,表明v点己是在最短路上                    continue;            vist[v]=mindis-D[v];            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( i=head[u]; i!=-1; i=edg[i].next){            v=edg[i].to;            if(edg[i].cap>0&&vist[u]+edg[i].d+D[v]!=mindis)                    continue;            vist[v]=mindis-D[v];            if( edg[i].cap-edg[i].flow>0 && Mind>dis[v]){                Mind=dis[v];                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;  //退一条边    }    return ans;}int numk[MAXN];void spfa(int s,int t,int n){    queue<int>q;    int inq[MAXN]={0},i;    for( i=1; i<=n; i++)        D[i]=INF;    D[t]=0; numk[t]=0;    q.push(t);    while(!q.empty()){        int u=q.front(); q.pop();        inq[u]=0;        for( i=head[u]; i!=-1; i=edg[i].next)        if(edg[i].d==INF&&D[edg[i].to]>D[u]+edg[i^1].d){            D[edg[i].to]=D[u]+edg[i^1].d;            numk[edg[i].to]=numk[u]+1;            if(inq[edg[i].to]==0)                inq[edg[i].to]=1,q.push(edg[i].to);        }        else if(edg[i].d==INF&&D[edg[i].to]==D[u]+edg[i^1].d&&numk[edg[i].to]>numk[u]+1)        {            numk[edg[i].to]=numk[u]+1;            if(inq[edg[i].to]==0)                inq[edg[i].to]=1,q.push(edg[i].to);        }    }}int main(){    int n,m,u,v,cost;    while(scanf("%d%d",&n,&m)>0)    {        init();        for(int i=1; i<=m; i++)        {            scanf("%d%d%d",&u,&v,&cost);            addEdg(u,v,cost);            addEdg(v,u,cost);        }        spfa(1,n,n);        int ans1,ans2;        ans2=m-numk[1];        mindis=D[1];        ans1=maxFlow_sap(1,n,n);        printf("%d %d\n",ans1,ans2);    }}


0 0
原创粉丝点击