题意: n个点,每个点有初始的值 ,三种 通道,1、隧道:可以用来躲避,有固定的容量,也可以用来传递。2、普通的道路,可以无限的通过。3、桥:不花费的话能通过一人,修之后可以无限通过。问最少花费最大可以隐藏人数。 可以建立最大流模型来求解,增加一个源点S,和一个汇点T。S向每个有人的点,连一条容量为人数的边,图中普通的u->v的有向边,连一条u->v的流量为无穷的边,桥的流量则为1。对于隧道,每个隧道可以虚拟出一个点,如u->v的隧道,可以虚拟一个点x,连接u->x,x->v的流量无穷的边,和x->T的流量为隧道人数上限的边,求解最大流即可得到最大人数。 现在考虑桥的问题,题目中说明了桥最多只有12座,故可以2^12枚举修复哪些桥,不修复的桥没有花费,连接的边流量为1,要修复的桥则计算花费,边的流量为无穷,这样进行2^12次最大流就可以得到最优解。 for(int i=0;i<(1<<sum);i++)可以枚举出所有的情况。 if(i&(1<<p[i]))表示枚举该桥修复。#include<cstdio>#include<queue>#include<cstring>#include<iostream>#include<algorithm>#include<cstring>#include<map>#include<string>#include <stdio.h>#include <iostream>#include <string.h>#include<queue>#include<cmath>using namespace std;const int inf=1<<30;const int M=500,ME=3009;const int INF=0x3f3fffff;//******************************最小费用最大流模版(可以单独用来求最大流,输入的时候,cost=0就可以:适用于u->v,只要符合了流量限制,只要通过了就花费,还有一种是:u->v,每单位的流量必须花费对少费用(poj2159模板))int Head[M],Next[ME],Num[ME],Flow[ME],Cap[ME],Cost[ME],vis[ME],Q[M],InQ[M],Len[M],pre_edge[M];int top; void clear() { memset(Head,-1,sizeof(Head)); memset(Flow,0,sizeof(Flow)); memset(vis,0,sizeof(vis)); top=0; } void addedge(int u,int v,int cap,int cost) { Next[top] = Head[u]; Num[top] = v; Cap[top] = cap; Cost[top] = cost; Head[u] = top++; Next[top] = Head[v]; Num[top] = u; Cap[top] = 0; Cost[top] = -cost; Head[v] = top++; } bool SPFA(int s,int t) { fill(Len,Len+M,INF); Len[s]=0; int head = -1,tail = -1,cur; Q[++head] = s; while(head != tail) { ++tail; if(tail >= M) tail = 0 ; cur = Q[tail]; for(int i = Head[cur];i != -1;i = Next[i]) { if(Cap[i]>Flow[i] && Len[Num[i]] > Len[cur] + Cost[i]) { Len[Num[i]] = Len[cur] + Cost[i]; pre_edge[Num[i]] = i; if(!InQ[Num[i]]) { InQ[Num[i]]=true; ++head; if(head >= M) head = 0; Q[head] = Num[i]; } } } InQ[cur]=false; } return Len[t] != INF; } int solve(int s,int t) { int ans= 0; while(SPFA(s,t)) { int cur = t,minflow = INF; while(cur != s) { if(minflow > Cap[pre_edge[cur]]-Flow[pre_edge[cur]]) minflow = Cap[pre_edge[cur]]-Flow[pre_edge[cur]]; cur = Num[pre_edge[cur] ^ 1]; } cur = t ; ans+=minflow; while(cur != s) { Flow[pre_edge[cur]] += minflow; Flow[pre_edge[cur] ^ 1] -= minflow; vis[pre_edge[cur]]=1; cur = Num[pre_edge[cur] ^ 1]; } } return ans;//最大流
int cost;//最小费用 for(int i=0;i<top;i++) //适用于u->v,只要符合了流量限制,只要通过了就花费,不管通过多少流量 { if(Flow[i]>0) cost+=Cost[i]; } }//****************************************************************int n,m;int val[M];int u[1509],v[1509],w[1509],p[1509];int uu[15],vv[15],ww[15];int main(){ while(scanf("%d%d",&n,&m)!=EOF) { clear(); int start=0; int end=n+25; int b=n+1; int k=0; for(int i=1;i<=n;i++) { scanf("%d",&val[i]); addedge(start,i,val[i],0); } for(int j=1;j<=m;j++) { scanf("%d%d%d%d",&u[j],&v[j],&w[j],&p[j]); if(p[j]==0) { addedge(u[j],v[j],inf,0); } else if(p[j]<0) { addedge(u[j],b,inf,0); addedge(b,v[j],inf,0); addedge(b++,end,w[j],0); } else { addedge(u[j],v[j],inf,0); uu[k]=u[j]; vv[k]=v[j]; ww[k]=w[j]; k++; p[k]=k; } } int an=solve(start,end); int mm=1<<k; int co=inf; for(int i=0;i<mm;i++) { clear(); b=n+1; for(int j=1;j<=n;j++) { addedge(start,j,val[j],0); } for(int j=1;j<=m;j++) { if(p[j]==0) { addedge(u[j],v[j],inf,0); } else if(p[j]<0) { addedge(u[j],b,inf,0); addedge(b,v[j],inf,0); addedge(b++,end,w[j],0); } else { addedge(u[j],v[j],1,0); if((1<<(p[j]-1))&i) addedge(u[j],v[j],inf,0); } } int tmp=solve(start,end); if(tmp==an) { int r=0; for(int t=0;t<k;t++) { if(i&(1<<t)) r+=ww[t]; } if(r<co) co=r; } } if(an==0) puts("Poor Heaven Empire"); else printf("%d %d\n",an,co); } return 0;}