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;
}