题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4309
题意:
给你n个城市,每座城市里会有一些人,m条单向边 u v w type ,边会出现三种,第一种是隧道type<0的时候,隧道最多20条,w是这个隧道里可以藏的人,第二种是普通的大道type==0的时候,那么w就作废,第三种是古桥type>0的时候,古桥在不修缮的时候最多只能通过一个人,但是如果你花费w的值将它修缮,那么就可以通过无限多个人,现在发生灾难大家都要逃向隧道躲避,问你在不计修缮成本的情况下最多能通过多少人,在保证人数还是这么多的情况下费用可以减少到多少。
做法:
一道复杂度让我很迷的网络流,明明理论上dinic网络流复杂度应该是n方m,这里还加上了状压的枚举要乘上(1<<12),因为告诉了你古桥的名字独一无二是十二星座中的一个,这样的话1e10应该是会超的,只能说数据水了...或者是没卡你这个算法。我还想着用费用流做来着。。状压我想到了不敢做啊。。。唉网络流真是佛系
因为告诉你两个城市之间的路径唯一,所以我就把隧道里可以存的人都放在了出来的城市上,这样的话点就最多是101个,边最多是(12+100+1000)*2那么多条。源点向城市连边,容量为人数,将古桥的边的下标进行记录,在枚举的时候直接改掉会快一点,其他的也稍微优化过了是700ms的样子。也是有点好奇400ms的人都是怎么过的。
#include<bits/stdc++.h>
using namespace std;
const int Ni = 120;
const int MAX = 1<<26;
const int maxm=2500;
struct Edge{
int u,v,c;
int next;
}edge[maxm],e[maxm];
int n,m,cnt,head[Ni],d[Ni],sp,tp;//原点,汇点
//理论复杂度n2*m
void add(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 bfs(){
queue <int> q;
memset(d,-1,sizeof(d));
d[sp]=0;
q.push(sp);
while(!q.empty()){
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=edge[i].next){
int u=edge[i].v;
if(d[u]==-1 && edge[i].c>0){
d[u]=d[cur]+1;
q.push(u);
}
}
}
return d[tp] != -1;
}
int dfs(int a,int b){
int r=0;
if(a==tp)return b;
for(int i=head[a];i!=-1 && r<b;i=edge[i].next)
{
int u=edge[i].v;
if(edge[i].c>0 && d[u]==d[a]+1)
{
int x=min(edge[i].c,b-r);
x=dfs(u,x);
r+=x;
edge[i].c-=x;
edge[i^1].c+=x;
}
}
if(!r)d[a]=-2;
return r;
}
int dinic(int sp,int tp){
int total=0,t;
while(bfs()){
while(t=dfs(sp,MAX))
total+=t;
}
return total;
}
struct spedge{
int id,cost;
}se[20];
int nse,x;
void init(){
cnt=0; nse=0;
memset(head,-1,sizeof(head));
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
sp=0,tp=n+1;
for(int i=1;i<=n;i++) scanf("%d",&x),add(sp,i,x);
for(int j=1;j<=m;j++){
int fr,to,co,ty;
scanf("%d%d%d%d",&fr,&to,&co,&ty);
if(ty>0){
se[nse].id=cnt,se[nse].cost=co;
nse++;
add(fr,to,1);
}
else add(fr,to,MAX);
if(ty<0) add(fr,tp,co);
}
memcpy(e,edge,sizeof(edge));
int ansflow=0,anscost=MAX;
for(int i=0;i<(1<<nse);i++){
memcpy(edge,e,sizeof(edge));
int flow=0,cost=0;
for(int j=0;j<nse;j++){
if(i&(1<<j)) {
cost+=se[j].cost;
edge[se[j].id].c=MAX;
}
}
flow=dinic(sp,tp);
if(flow>ansflow){
ansflow=flow; anscost=cost;
}
else if(flow==ansflow&&cost<anscost){
anscost=cost;
}
}
if(ansflow==0) printf("Poor Heaven Empire\n");
else printf("%d %d\n",ansflow,anscost);
}
return 0;
}