zoukankan      html  css  js  c++  java
  • hdu3416 Marriage Match IV(最短路+最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3416

    题目意思:有n个点,m条带权有向边,求点a到b有几条最短路(每条路只能走一次)。

    先说一下写题过程,那叫一个惨啊!wa了20多遍,开始还没学网络流,以为就是最短路加搜索就可以,开始的思路是先求出各点到终点的最短路,再给路编号,搜索路,搜索到一条最短路就标记这条路走过的路全部编号,下次就不能搜索了,直到没有最短路为止。但最后错了。发现有一组反例:

     5  6

    1 2 1

    2 3 1

    3 5 1

    1 3 2

    2 4 1

    4 5 1

    它找不要最优解,本来有两条,它只会找到1->2->3->5这一条。

    看了一下题解说是最短路加最大流。那我就学了一下网络流,发现最终的思路是:先最短路求出图的最短路上的核心边,再用核心边建权为1的网络流图,最后求一遍最大流即可。

    最短路核心边就是可以构成最短路的边。最短路的核心边才可能是要走的路,而设为权为1的网络流,可以从汇点的最大流看出从源点有多少流量流到汇点,即有几条路通过。

    细节看代码:

    /*
    hdu3416 
    题目:有n个点,m条带权有向边,求点a到b有几条最短路(每条路只能走一次)。
    思路:先最短路求出图的最短路上的核心边,再用核心边建权为1的网络流图,最后求一遍最大流即可。 
    */
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn=1100;
    const int maxm=1e5+100;
    struct node{
        int u,v,w,next;
    }e[maxm],e2[2*maxm];
    int head[maxm],head2[2*maxm],d[maxn];
    int depth[2*maxm],visit[maxn];
    int n,m,t,a,b,cnt,cnt2;
    //e是原来的图,e2是建的网络流。 
    void init(){
        memset(head,-1,sizeof(head));
        memset(head2,-1,sizeof(head2));
        memset(visit,0,sizeof(visit));
        memset(d,0x3f,sizeof(d));
        cnt=cnt2=0;
    }
    
    void add(int u,int v,int w){//原图连边 
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt++;
    }
    
    void add2(int u,int v,int w){
        e2[cnt2].u=u;
        e2[cnt2].v=v;
        e2[cnt2].w=w;
        e2[cnt2].next=head2[u];
        head2[u]=cnt2++;
    }
    
    void spfa(){//求最短路 
        queue<int> q;
        q.push(a);
        visit[a]=1;
        d[a]=0;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            visit[u]=0;
            for(int i=head[u];i!=-1;i=e[i].next){
                int v=e[i].v;
                int w=e[i].w;
                if(d[v]>d[u]+w){
                    d[v]=d[u]+w;
                    if(!visit[v]){
                        visit[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    
    void creat_map(){//建网络流 
        for(int i=0;i<cnt;i++){
            int u=e[i].u;
            int v=e[i].v;
            int w=e[i].w;
            if((d[u]+w==d[v])&&(d[u]<inf&&d[v]<inf)){
                /*一定要判断这条路合法,即 d[u]<inf&&d[v]<inf,我在这卡了一组数据,测试样例:
                 99
                 3 2
                 1 2 1
                 1 2 2
                 1 3
                 */ 
                add2(u,v,1);//正向边建权为1 
                add2(v,u,0);//反向边建为0 
            }
        }
    }
    
    bool bfs(){//dinic分层 
        queue<int> q;
        memset(depth,0,sizeof(depth));
        q.push(a);
        depth[a]=1;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            if(u==b)
                return true;
            for(int i=head2[u];i!=-1;i=e2[i].next){
                int v=e2[i].v;
                int w=e2[i].w;
                if(!depth[v]&&w){
                    depth[v]=depth[u]+1;
                    q.push(v);
                }
            }
        }
        return false;
    }
    
    int dfs(int u,int dis){//dinic的dfs搜索增广路 
        if(u==b)
            return dis;
        int res=0;
        for(int i=head2[u];i!=-1;i=e2[i].next){
            int v=e2[i].v;
            int w=e2[i].w;
            if((depth[v]==depth[u]+1)&&w){
                int di=dfs(v,min(w,dis-res));
                e2[i].w-=di;
                e2[i^1].w+=di;
                res+=di;
                if(res==dis)    
                    return res;
            }
        }
        return res;
    }
    
    void dinic(){
        int ans=0;
        while(bfs()){
                ans+=dfs(a,inf);
        }
        printf("%d
    ",ans);
    }
    
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            init();
            for(int i=0;i<m;i++){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
            }
            scanf("%d%d",&a,&b);
            spfa();
            creat_map();
            dinic();
        }
        return 0;
    }

     

  • 相关阅读:
    使用bootstrap建立响应式网页——通栏轮播图(carousel)
    java的HashMap与ConcurrentHashMap
    JVM性能调优
    Spring注解@Component、@Repository、@Service、@Controller区别
    Java过滤器与SpringMVC拦截器之间的关系与区别
    Java线程(二):线程同步synchronized和volatile
    Java线程(一):线程安全与不安全
    MySQL 加锁处理分析
    Spring 事务机制详解
    使用jsonp跨域调用百度js实现搜索框智能提示,并实现鼠标和键盘对弹出框里候选词的操作【附源码和在线测试地址】
  • 原文地址:https://www.cnblogs.com/xiongtao/p/10313927.html
Copyright © 2011-2022 走看看