zoukankan      html  css  js  c++  java
  • hdu4309(网络流)

    2012多校联合赛第一场,第十题。

    先不考虑可以修复的桥的性质, 则可以将模型简化为n个点的人通过有通过人数上限的有向边,到达一些有人数上限的特殊的边(隧道)。

    可以建立最大流模型来求解, 增加一个源点S,和一个汇点T。 S向每个有人的点,连一条容量为人数的边, 图中普通的u->v的有向边,连一条u->v的流量为无穷的边, 桥的流量则为1。 对于隧道,每个隧道可以虚拟出一个点,如u->v的隧道,可以虚拟一个点x,连接u->x,x->v的流量无穷的边, 和x->T的流量为隧道人数上限的边, 求解最大流即可得到最大人数。

    现在考虑桥的问题,题目中说明了桥最多只有12座,故可以2^12枚举修复哪些桥,不修复的桥没有花费,连接的边流量为1,要修复的桥则计算花费,边的流量为无穷,这样进行2^12次最大流就可以得到最优解。

    看了题解后,建图,1Y。

    2^12枚举,对桥建边很戏剧,用递归,很好玩。

    发现我现在的编程状态很好,200行编下来,基本上想到什么就能编出来什么,网络流,递归,枚举。。以后只要相信自己就好。

    相信自己的编码能力!!!

    View Code
    /*
    Problem : 4309 ( Seikimatsu Occult Tonneru )     Judge Status : Accepted
    RunId : 6291376    Language : G++    Author : 2010201211
    Time : 1687MS Memory : 608K
    */
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    using namespace std;
    #define E 30000
    #define V 1102
    #define inf 0xffff
    struct Edge{
        int u,v,c,next;
    }edge[E];
    int n,m,cnt;
    int cou;
    int dist[V];
    int head[V];
    int que[V];
    int sta[V];
    void init(){
        cnt=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v,int c){
        edge[cnt].u=u;edge[cnt].v=v;edge[cnt].c=c;
        edge[cnt].next=head[u];head[u]=cnt++;
    
        edge[cnt].u=v;edge[cnt].v=u;edge[cnt].c=0;
        edge[cnt].next=head[v];head[v]=cnt++;
    }
    int dinic(int s,int t){
        int ans=0;
        while(true){
            int left,right,u,v;
    
            memset(dist,-1,sizeof(dist));
            left=right=0;
            que[right++]=s;
            dist[s]=0;
    
            while(left<right){
                u=que[left++];
                for(int k=head[u];k!=-1;k=edge[k].next){
                    u=edge[k].u;
                    v=edge[k].v;
                    if(edge[k].c>0 && dist[v]==-1){
                        dist[v]=dist[u]+1;
                        que[right++]=v;
                        if(v==t){
                            left=right;
                            break;
                        }
                    }
                }
            }
    
            if(dist[t]==-1) break;
    
            int top=0;
            int now=s;
            while(true){
                if(now!=t){
                    int k;
                    for(k=head[now];k!=-1;k=edge[k].next){
                        if(edge[k].c > 0 && dist[edge[k].u]+1==dist[edge[k].v]) break;
                    }
                    if(k!=-1){
                        sta[top++]=k;
                        now=edge[k].v;
                    }
                    else{
                        if(top==0) break;
                        dist[edge[sta[--top]].v]=-1;
                        now=edge[sta[top]].u;
                    }
                }
                else{
                    int flow=inf,ebreak;
                    for(int i=0;i<top;i++){
                        if(flow>edge[sta[i]].c){
                            flow=edge[sta[i]].c;
                            ebreak=i;
                        }
                    }
                    ans+=flow;
                    for(int i=0;i<top;i++){
                        edge[sta[i]].c-=flow;
                        edge[sta[i]^1].c+=flow;
                    }
                    now = edge[sta[ebreak]].u;
                    top = ebreak;
                }
            }
        }
        return ans;
    }
    int r,b,t;
    int p[V];
    struct T{
        int u,v,c;
    }road[E],bridge[E],tunnel[E];
    bool fb[12];
    struct R{
        int num,cost;
    }res[5000];
    void build(){
        init();
        for(int i=1;i<=n;i++){
            addedge(0,i,p[i]);
        }
        for(int i=0;i<r;i++){
            addedge(road[i].u,road[i].v,inf);
        }
        for(int i=0;i<t;i++){
            addedge(tunnel[i].u,n+i+1,inf);
            addedge(n+i+1,tunnel[i].v,inf);
            addedge(n+i+1,n+t+1,tunnel[i].c);
        }
    }
    
    void dfs(int s){//2^12枚举,对桥建边。
        if(s==b){
            int sum=0;
            build();
            for(int i=0;i<b;i++){
                if(fb[i]==0){
                    addedge(bridge[i].u,bridge[i].v,1);
                    sum+=0;
                }
                else{
                    addedge(bridge[i].u,bridge[i].v,inf);
                    sum+=bridge[i].c;
                }
            }
            res[cou].num=dinic(0,n+t+1);
            res[cou++].cost=sum;
            return ;
        }
        fb[s]=0;
        dfs(s+1);
        fb[s]=1;
        dfs(s+1);
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        int a,bb,c,d;
        while(cin >> n >> m){
            for(int i=1;i<=n;i++){
                cin >> p[i];
            }
            r=b=t=0;
            for(int i=1;i<=m;i++){
                cin >> a >> bb >> c >> d;
                if(d<0){
                    tunnel[t].u=a;
                    tunnel[t].v=bb;
                    tunnel[t++].c=c;
                }
                if(d==0){
                    road[r].u=a;
                    road[r++].v=bb;
                }
                if(d>0){
                    bridge[b].u=a;
                    bridge[b].v=bb;
                    bridge[b++].c=c;
                }
            }
            memset(fb,0,sizeof(fb));
            for(int i=0;i<5000;i++){
                res[i].cost=0;
                res[i].num =0;
            }
    
            cou=0;
            dfs(0);
            int minc=inf,maxc=-1;
            for(int i=0;i<cou;i++){
                if(res[i].num>maxc){
                    maxc=res[i].num;
                }
            }
            for(int i=0;i<cou;i++){
                if(res[i].num==maxc){
                    if(res[i].cost<minc){
                        minc=res[i].cost;
                    }
                }
            }
            if(maxc==0) printf("Poor Heaven Empire\n");
            else printf("%d %d\n",maxc,minc);
        }
        return 0;
    }
  • 相关阅读:
    贪心算法1000
    贪心算法1006
    1012
    贪心算法1016
    贪心算法1001
    贪心算法1004
    Java作业1
    指针数组与数组指针的区别
    Java 中对类进行排序的方法(转)
    java习题1
  • 原文地址:https://www.cnblogs.com/markliu/p/2603044.html
Copyright © 2011-2022 走看看