题意:
有三种不同类型的边,一种可以在里面放人,一种可以任意多人穿过,一种可以过一个人,如果通过了一个人之后可以选择增加花费使得可以通过无限的人数。有N个城市,要把尽可能多的人放在第一种里面,问最少需要多少花费。
思路:
可以转化为网络流模型,第一种边拆开就好,如(x,y)连成,x->u,u->T,x-y,这样就好,其他的就枚举第三种选择那些就好,(因为第三种只有12条)。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<vector>
using namespace std;
typedef __int64 ll;
const int maxnode=4000+5;
const int maxedge=1000000+5;
const int oo=1000000000;
struct Dinic
{
int node,src,dest,nedge;
int head[maxnode],point[maxedge],next[maxedge],flow[maxedge],capa[maxedge];
int dist[maxnode],Q[maxnode],work[maxnode];
void init(int _node,int _src,int _dest)
{
node=_node;
src=_src;
dest=_dest;
for(int i=0; i<node; i++) head[i]=-1;
nedge=0;
}
void addedge(int u,int v,int c1,int c2)
{
point[nedge]=v,capa[nedge]=c1,flow[nedge]=0,next[nedge]=head[u],head[u]=(nedge++);
point[nedge]=u,capa[nedge]=c2,flow[nedge]=0,next[nedge]=head[v],head[v]=(nedge++);
}
bool dinic_bfs()
{
memset(dist,255,sizeof(dist));
dist[src]=0;
int sizeQ=0;
Q[sizeQ++]=src;
for(int cl=0; cl<sizeQ; cl++)
{
for(int k=Q[cl],i=head[k]; i>=0; i=next[i])
{
if(flow[i]<capa[i] && dist[point[i]]<0)
{
dist[point[i]]=dist[k]+1;
Q[sizeQ++]=point[i];
}
}
}
return dist[dest]>=0;
}
int dinic_dfs(int x,int exp)
{
if(x==dest) return exp;
for(int &i=work[x]; i>=0; i=next[i])
{
int v=point[i],tmp;
if(flow[i]<capa[i] && dist[v]==dist[x]+1 && (tmp = dinic_dfs(v,min(exp,capa[i]-flow[i])))>0)
{
flow[i]+=tmp;
flow[i^1]-=tmp;
return tmp;
}
}
return 0;
}
int dinic_flow()
{
int result=0;
while(dinic_bfs())
{
for(int i=0; i<node; i++) work[i]=head[i];
while(1)
{
int delta=dinic_dfs(src,oo);
if(delta==0) break;
result +=delta;
}
}
return result;
}
} Solver;
int N,m;
int num_tunnel,num_modern,num_ancient;
int num[110];
int tun[33],modern[1010],anc[33];
int ut[33],vt[33],um[1010],vm[1010],ua[33],va[33];
int res,sum_cost;
bool choose[33];
void cal()
{
int tcost=0;
for(int i=1; i<=num_ancient; i++)
{
if(choose[i])tcost+=anc[i];
}
//printf("tcost=%d\n",tcost);
if(tcost>=sum_cost)return;
Solver.init(num_tunnel+N+2,0,num_tunnel+N+1);
for(int i=1; i<=N; i++)
{
Solver.addedge(0,i,num[i],0);
}
for(int i=1; i<=num_tunnel; i++)
{
Solver.addedge(N+i,num_tunnel+N+1,tun[i],0);
Solver.addedge(ut[i],N+i,oo,0);
//Solver.addedge(vt[i],N+i,oo,0);
Solver.addedge(ut[i],vt[i],oo,0);
}
for(int i=1; i<=num_modern; i++)
{
Solver.addedge(um[i],vm[i],oo,0);
}
for(int i=1; i<=num_ancient; i++)
{
if(choose[i])
{
Solver.addedge(ua[i],va[i],oo,0);
}
else
{
Solver.addedge(ua[i],va[i],1,0);
}
}
int t=Solver.dinic_flow();
if(t>=res)
{
sum_cost=tcost;
}
}
void first()
{
Solver.init(num_tunnel+N+2,0,num_tunnel+N+1);
for(int i=1; i<=N; i++)
{
Solver.addedge(0,i,num[i],0);
}
for(int i=1; i<=num_tunnel; i++)
{
Solver.addedge(N+i,num_tunnel+N+1,tun[i],0);
Solver.addedge(ut[i],N+i,oo,0);
// Solver.addedge(vt[i],N+i,oo,0);
Solver.addedge(ut[i],vt[i],oo,0);
}
for(int i=1; i<=num_modern; i++)
{
Solver.addedge(um[i],vm[i],oo,0);
}
for(int i=1; i<=num_ancient; i++)
{
Solver.addedge(ua[i],va[i],oo,0);
}
res=Solver.dinic_flow();
}
void dfs(int ind)
{
if(ind>num_ancient)
{
//for(int i=1;i<=num_ancient;i++)printf("%d ",choose[i]);printf("\n");
cal();
}
else
{
choose[ind]=false;
dfs(ind+1);
choose[ind]=true;
dfs(ind+1);
choose[ind]=false;
}
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
scanf("%d",&m);
num_tunnel=0;
num_ancient=0;
num_modern=0;
sum_cost=0;
for(int i=1; i<=N; i++)
{
scanf("%d",&num[i]);
}
for(int i=1; i<=m; i++)
{
int u,v,w,p;
scanf("%d%d%d%d",&u,&v,&w,&p);
if(p<0)
{
tun[++num_tunnel]=w;
ut[num_tunnel]=u;
vt[num_tunnel]=v;
}
else if(p==0)
{
modern[++num_modern]=w;
um[num_modern]=u;
vm[num_modern]=v;
}
else
{
sum_cost+=w;
anc[++num_ancient]=w;
ua[num_ancient]=u;
va[num_ancient]=v;
}
}
//printf("@@%d\n",sum_cost);
first();
if(res<=0)
{
printf("Poor Heaven Empire\n");
}
else
{
memset(choose,false,sizeof(choose));
dfs(1);
printf("%d %d\n",res,sum_cost);
}
}
return 0;
}