hdu 4309 Seikimatsu Occult Tonneru

本文通过最大流模型解决城市桥梁修复问题,利用源点S和汇点T建立模型,通过增加流量来确定最优修复方案,确保城市交通畅通。

2^12枚举修复哪些桥,不修复的桥没有花费,连接的边流量为1,要修复的桥则计算花费,边的流量为无穷,建立最大流模型来求解,增加一个源点S,和一个汇点T。S向每个有人的点,连一条容量为人数的边,图中普通的u->v的有向边,连一条u->v的流量为无穷的边,对于u->v的隧道,可以连接u->v的流量无穷的边,和u->T的流量为隧道人数上限的边,求解最大流即可。

#include<stdio.h>
#include<string.h>

#define N 1105
#define oo 2000000000

int head[N],idx;

struct edge{

    int u,v,nt,cap;
    edge(){}
    edge(int u,int v,int nt,int cap):u(u),v(v),nt(nt),cap(cap){}
}e[N*N];

int level[N],cur[N],ps[N];
int s,t;
int x[N],y[N],z[N],p[N],pv[N];

void AddEdge(int u,int v,int c){
    e[idx]=edge(u,v,head[u],c);head[u]=idx++;
    e[idx]=edge(v,u,head[v],0);head[v]=idx++;
}

int dinic(){


    int i,j,k,top,f,r;
    int tr,res=0;
    while(1)
    {

        memset(level,-1,sizeof(level));

        for(f=level[ps[0]=s]=0,r=1;f!=r;)
        for(i=ps[f++],j=head[i];j!=-1;j=e[j].nt)
        {
            if(e[j].cap>0&&-1==level[k=e[j].v])
            {
                level[k]=level[i]+1;
                ps[r++]=k;
                if(k==t) {f=r;break;}
            }
        }
        if(-1==level[t]) break;

        memcpy(cur,head,sizeof(head));

        for(i=s,top=0;;)
        {
            if(i==t)
            {
                tr=oo;
                for(k=0;k<top;k++)
                  if(e[ps[k]].cap<tr) tr=e[ps[f=k]].cap;

                for(k=0;k<top;k++)
                   e[ps[k]].cap-=tr,e[ps[k]^1].cap+=tr;
                res+=tr;
                i=e[ps[top=f]].u;
            }

            for(j=cur[i];j!=-1;j=cur[i]=e[cur[i]].nt)
               if(e[j].cap>0&&level[i]+1==level[e[j].v]) break;

            if(cur[i]!=-1){
                ps[top++]=cur[i];
                i=e[cur[i]].v;
              }
            else
            {
                if(!top) break;
                level[i]=-1;
                i=e[ps[--top]].u;
            }
        }
    }
    return res;
}

int n,m;

int main(){

    while(scanf("%d%d",&n,&m)!=EOF)
    {

        int cnt=0;
        for(int i=1;i<=n;i++) scanf("%d",pv+i);
        bool flag=0;

        for(int i=0;i<m;i++){

            scanf("%d%d%d%d",x+i,y+i,z+i,p+i);
            if(p[i]<0) flag=1;
            if(p[i]>0) cnt++;
        }

        if(!flag)
        {
            puts("Poor Heaven Empire");
            continue;
        }


        int maxnum=0,minsum=0;
        s=0,t=n+1;

        for(int w=0;w<(1<<cnt);w++){

            memset(head,-1,sizeof(head));
            idx=0;

            int j=0,i;
            int num,sum=0;

            for(int i=1;i<=n;i++) AddEdge(s,i,pv[i]);

            for(int i=0;i<m;i++)
            {
                if(p[i]==0) {AddEdge(x[i],y[i],oo);}

                if(p[i]<0){AddEdge(x[i],t,z[i]);AddEdge(x[i],y[i],oo);}

                if(p[i]>0)
                 {

                    if(w&(1<<j))
                    {
                        AddEdge(x[i],y[i],oo);
                        sum+=z[i];
                    }
                    else AddEdge(x[i],y[i],1);

                    j++;
                }
            }

            num=dinic();

            if(num>maxnum||(num==maxnum&&sum<minsum)) maxnum=num,minsum=sum;

        }
        if(maxnum==0)  puts("Poor Heaven Empire");
        else
        printf("%d %d\n",maxnum,minsum);
    }
}
/*

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值