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


    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 9 1 2 2 2 3 2 2 4 1 3 5 3 4 5 4 5 8 1 1 6 2 6 7 5 7 8 1
     

    Sample Output
    2 6
     

    Source
     

    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 int
    
    const 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
    ",ans1,ans2);
        }
    }
    


  • 相关阅读:
    Rust交叉编译Mac编译Linux/Windows平台
    SpringBoot 如何生成接口文档
    Echarts + Python 实现的动态实时大屏范例
    计算机中的0.1+0.2=0.3吗?(无可避免的浮点误差)
    Odin线刷失败的常见错误原因分析及解决方法(转载)
    Odin3 刷机工具刷机教程, BL、AP、CP 与 CSC 是什么意思(转载)
    各种常见USB接口类型
    三星S8+手机,刷机经验
    小米8手机,MIUI由12.5降级到9.5、安卓由10降到8;先ROOT,再安装Magisk、Xposed的步骤
    手机刷机相关,若干名词
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6911318.html
Copyright © 2020-2023  润新知