题意:
在一个地图上..有3种桥..第一种桥是能通过任意多的人.并且可以躲藏一定数量的人.第一种桥是可以通过任意多数量的人..第三种桥很古老.若不修缮只能让一个人通过.桥就损坏了..或者用一定的花费将桥修好.让上面可以过任何多的人..问最多能藏多少人?并且保证这个最多. 让修复第三类桥的费用最小...
题解:
由于第三类桥至多12个..所以用二进制暴力枚举修善哪些桥..然后用网络流找当前状态的大难...开始看着最大匹配..最小费用..就用最小费用最大流做了..但后来发现有bug.想不到合理的构图了..这题就用最大流来做..做边:
1、超级原点向所有的点做边....容量为这个点上的人数...
2、当桥第一类桥时..(x,y)在两点间增加一个点x'..那么做边为x->x‘容量'无穷大.x'->y容量无穷大.x'->e为其边所能躲藏的最多人数
3、当桥为第二类时.x->y为无穷大..
4、当桥为第三类时..若当前桥在枚举的状态中已修复..则做边x->y容量无穷大..若没修复..则做边x->y容量为1...
跑最大流可以知道当前最多能让多少人躲藏好..同时根据当前第三类桥的状态可以知道付出的花费是多少..根据题意更新答案就好...
Program:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#define MAXN 505
#define MAXM 50005
#define oo 1000000007
#define ll long long
using namespace std;
struct Dinic
{
struct node
{
int c,u,v,next;
}edge[MAXM];
int ne,head[MAXN];
int cur[MAXN], ps[MAXN], dep[MAXN];
void initial()
{
ne=2;
memset(head,0,sizeof(head));
}
void addedge(int u, int v,int c)
{
edge[ne].u=u,edge[ne].v=v,edge[ne].c=c,edge[ne].next=head[u];
head[u]=ne++;
edge[ne].u=v,edge[ne].v=u,edge[ne].c=0,edge[ne].next=head[v];
head[v]=ne++;
}
int MaxFlow(int s,int t)
{
int tr, res = 0;
int i,j,k,f,r,top;
while(1)
{
memset(dep, -1, sizeof(dep));
for(f=dep[ps[0]=s]=0,r=1;f!= r;)
for(i=ps[f++],j=head[i];j;j=edge[j].next)
if(edge[j].c&&dep[k=edge[j].v]==-1)
{
dep[k]=dep[i]+1;
ps[r++]=k;
if(k == t){ f=r; break; }
}
if(dep[t]==-1) break;
memcpy(cur,head,sizeof(cur));
i=s,top=0;
while(1)
{
if(i==t)
{
for(tr=oo,k=0;k<top;k++)
if(edge[ps[k]].c<tr)
tr=edge[ps[f=k]].c;
for(k=0;k<top;k++)
{
edge[ps[k]].c-=tr;
edge[ps[k]^1].c+=tr;
}
i=edge[ps[top=f]].u;
res+= tr;
}
for(j=cur[i];cur[i];j=cur[i]=edge[cur[i]].next)
if(edge[j].c && dep[i]+1==dep[edge[j].v]) break;
if(cur[i]) ps[top++]=cur[i],i=edge[cur[i]].v;
else
{
if(!top) break;
dep[i]=-1;
i=edge[ps[--top]].u;
}
}
}
return res;
}
}T;
int num[105],N1,N2;
struct node
{
int x,y,w,p;
}L[1005],LL[20];
int doit(int n,int k)
{
int s=n<<2,e=s|1,i,x,y,w,p;
T.initial();
for (i=0;i<N2;i++)
if (k&(1<<i)) T.addedge(LL[i].x,LL[i].y,oo);
else T.addedge(LL[i].x,LL[i].y,1);
for (i=1;i<=n;i++) T.addedge(s,i,num[i]);
for (i=1;i<=N1;i++)
{
x=L[i].x,y=L[i].y,w=L[i].w,p=L[i].p;
if (!p) T.addedge(x,y,oo);
else T.addedge(x,x+n,oo),T.addedge(x+n,y,oo),
T.addedge(x+n,e,w);
}
return T.MaxFlow(s,e);
}
int fee(int x)
{
int s=0,i;
for (i=0;i<N2;i++)
if (x&(1<<i)) s+=LL[i].w;
return s;
}
int main()
{
int i,s,e,n,m,x,y,w,p;
while (~scanf("%d%d",&n,&m))
{
for (i=1;i<=n;i++) scanf("%d",&num[i]);
N1=N2=0;
for (i=1;i<=m;i++)
{
scanf("%d%d%d%d",&x,&y,&w,&p);
if (p<=0) L[++N1].x=x,L[N1].y=y,L[N1].w=w,L[N1].p=p;
else LL[N2].x=x,LL[N2].y=y,LL[N2].w=w,N2++;
}
int ansF=-1,ansM;
for (x=0;x<(1<<N2);x++)
{
int MF=doit(n,x),M=fee(x);
if (ansF<MF) ansF=MF,ansM=M;
else
if (ansF==MF && ansM>M) ansM=M;
}
if (!ansF) printf("Poor Heaven Empire\n");
else printf("%d %d\n",ansF,ansM);
}
return 0;
}