MUTC 1 E - Seikimatsu Occult Tonneru 枚举 网络流
Seikimatsu Occult Tonneru
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1341 Accepted Submission(s): 313
Problem Description
During the world war, to avoid the upcoming Carpet-bombing from The Third Reich, people in Heaven Empire went to Great Tunnels for sheltering.
There are N cities in Heaven Empire, where people live, with 3 kinds of directed edges connected with each other. The 1st kind of edges is one of Great Tunnels( no more than 20 tunnels) where a certain number of people can hide here; people can also go through one tunnel from one city to another. The 2nd kind of edges is the so-called Modern Road, which can only let people go through. The 3rd kind of edges is called Ancient Bridge and all the edges of this kind have different names from others, each of which is named with one of the twelve constellations( such as Libra, Leo and so on); as they were build so long time ago, they can be easily damaged by one person's pass. Well, for each bridge, you can spend a certain deal of money to fix it. Once repaired, the 3rd kind of edges can let people pass without any limitation, namely, you can use one bridge to transport countless people. As for the former two kinds of edges, people can initially go through them without any limitation.
We want to shelter the most people with the least money.
Now please tell me the largest number of people who can hide in the Tunnels and the least money we need to spend to realize our objective.
There are N cities in Heaven Empire, where people live, with 3 kinds of directed edges connected with each other. The 1st kind of edges is one of Great Tunnels( no more than 20 tunnels) where a certain number of people can hide here; people can also go through one tunnel from one city to another. The 2nd kind of edges is the so-called Modern Road, which can only let people go through. The 3rd kind of edges is called Ancient Bridge and all the edges of this kind have different names from others, each of which is named with one of the twelve constellations( such as Libra, Leo and so on); as they were build so long time ago, they can be easily damaged by one person's pass. Well, for each bridge, you can spend a certain deal of money to fix it. Once repaired, the 3rd kind of edges can let people pass without any limitation, namely, you can use one bridge to transport countless people. As for the former two kinds of edges, people can initially go through them without any limitation.
We want to shelter the most people with the least money.
Now please tell me the largest number of people who can hide in the Tunnels and the least money we need to spend to realize our objective.
Input
Multiple Cases.
The first line, two integers: N (N<=100), m (m<=1000). They stands for the number of cities and edges.
The next line, N integers, which represent the number of people in the N cities.
Then m lines, four intergers each: u, v, w, p (1<=u, v<=N, 0<=w<=50). A directed edge u to v, with p indicating the type of the edge: if it is a Tunnel then p < 0 and w means the maximum number people who can hide in the the tunnel; if p == 0 then it is a Modern Road with w means nothing; otherwise it is an Ancient Bridge with w representing the cost of fixing the bridge. We promise there are no more than one edge from u to v.
The first line, two integers: N (N<=100), m (m<=1000). They stands for the number of cities and edges.
The next line, N integers, which represent the number of people in the N cities.
Then m lines, four intergers each: u, v, w, p (1<=u, v<=N, 0<=w<=50). A directed edge u to v, with p indicating the type of the edge: if it is a Tunnel then p < 0 and w means the maximum number people who can hide in the the tunnel; if p == 0 then it is a Modern Road with w means nothing; otherwise it is an Ancient Bridge with w representing the cost of fixing the bridge. We promise there are no more than one edge from u to v.
Output
If nobody can hide in the Tunnels, print “Poor Heaven Empire”, else print two integers: maximum number and minimum cost.
Sample Input
4 4 2 1 1 0 1 2 0 0 1 3 0 0 2 4 1 -1 3 4 3 -1 4 4 2 1 1 0 1 2 0 0 1 3 3 1 2 4 1 -1 3 4 3 -1
Sample Output
4 0 4 3
Author
BUPT
Source
Recommend
zhuyuanchen520
-----------------
最大流
建图:
从S向城市i连接一条容量为人数的边。
对每条边
①p<0时,从u向T连接一条容量为人数的边,从u向v连接一条容量为OO的边
②p=0时,从u向T连接一条容量为无穷大的边
③p>0时,枚举是否修复。修复的情况从u向v连接一条容量为OO的边,累积花费;不修复的情况从u向v连接一条容量为1的边,无花费。
枚举每条待修复的边,最多有2^12种方案。
-----------------
用黄大神的Dinic模板AC,用白书的模板超时
-----------------
更快的
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <set> using namespace std; const int OO=1e9; const int maxm=111111; const int maxn=999; struct edgenode { int to,flow,next; }; struct Dinic { int node,src,dest,edge; int head[maxn],work[maxn],dis[maxn],q[maxn]; edgenode edges[maxm]; void prepare(int _node,int _src,int _dest) { node=_node,src=_src,dest=_dest; for (int i=0; i<node; i++) head[i]=-1; edge=0; } void addedge(int u,int v,int c) { edges[edge].flow=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; edges[edge].flow=0,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++; } bool Dinic_bfs() { int i,u,v,l,r=0; for (i=0; i<node; i++) dis[i]=-1; dis[q[r++]=src]=0; for (l=0; l<r; l++){ for (i=head[u=q[l]]; i!=-1; i=edges[i].next){ if (edges[i].flow&&dis[v=edges[i].to]<0){ dis[q[r++]=v]=dis[u]+1; if (v==dest) return true; } } } return false; } int Dinic_dfs(int u,int exp) { if (u==dest) return exp; for (int &i=work[u],v,tmp; i!=-1; i=edges[i].next){ if (edges[i].flow&&dis[v=edges[i].to]==dis[u]+1&& (tmp=Dinic_dfs(v,min(exp,edges[i].flow)))>0){ edges[i].flow-=tmp; edges[i^1].flow+=tmp; return tmp; } } return 0; } int Dinic_flow() { int i,ret=0,delta; while (Dinic_bfs()){ for (i=0; i<node; i++) work[i]=head[i]; while ( delta=Dinic_dfs(src,OO) ) ret+=delta; } return ret; } }solver; int ogc[14]; int cst[14]; int cnt; int ww[maxn]; int main() { int n,m; int mincost,maxnum,cost,num; while (~scanf("%d%d",&n,&m)) { cnt=0; solver.prepare(n+2,0,n+1); for (int i=1;i<=n;i++) { scanf("%d",&ww[i]); solver.addedge(solver.src,i,ww[i]); } for (int i=0;i<m;i++) { int u,v,w,p; scanf("%d%d%d%d",&u,&v,&w,&p); if (p<0) { solver.addedge(u,solver.dest,w); solver.addedge(u,v,OO); } if (p>0) { solver.addedge(u,v,1); cst[cnt]=w; ogc[cnt++]=solver.edge-2; } if (p==0) { solver.addedge(u,v,OO); } } mincost=0; maxnum=0; for (int i=0;i<(1<<cnt);i++) { cost=0; num=0; for (int k=0;k<solver.edge;k+=2) { solver.edges[k].flow+=solver.edges[k^1].flow; solver.edges[k^1].flow=0; } for (int j=0;j<cnt;j++) { if (i&(1<<j)) { solver.edges[ogc[j]].flow=OO; cost+=cst[j]; } else { solver.edges[ogc[j]].flow=1; } } num=solver.Dinic_flow(); if (num>maxnum) { maxnum=num; mincost=cost; } else if (num==maxnum&&cost<mincost) { mincost=cost; } } if (maxnum>0) { printf("%d %d\n",maxnum,mincost); } else { puts("Poor Heaven Empire"); } } return 0; }
---------------
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <set> using namespace std; const int OO=1e9; const int maxm=111111; const int maxn=999; struct edgenode { int to,flow,next; }; struct Dinic { int node,src,dest,edge; int head[maxn],work[maxn],dis[maxn],q[maxn]; edgenode edges[maxm]; void prepare(int _node,int _src,int _dest) { node=_node,src=_src,dest=_dest; for (int i=0; i<node; i++) head[i]=-1; edge=0; } void addedge(int u,int v,int c) { edges[edge].flow=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; edges[edge].flow=0,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++; } bool Dinic_bfs() { int i,u,v,l,r=0; for (i=0; i<node; i++) dis[i]=-1; dis[q[r++]=src]=0; for (l=0; l<r; l++){ for (i=head[u=q[l]]; i!=-1; i=edges[i].next){ if (edges[i].flow&&dis[v=edges[i].to]<0){ dis[q[r++]=v]=dis[u]+1; if (v==dest) return true; } } } return false; } int Dinic_dfs(int u,int exp) { if (u==dest) return exp; for (int &i=work[u],v,tmp; i!=-1; i=edges[i].next){ if (edges[i].flow&&dis[v=edges[i].to]==dis[u]+1&& (tmp=Dinic_dfs(v,min(exp,edges[i].flow)))>0){ edges[i].flow-=tmp; edges[i^1].flow+=tmp; return tmp; } } return 0; } int Dinic_flow() { int i,ret=0,delta; while (Dinic_bfs()){ for (i=0; i<node; i++) work[i]=head[i]; while ( delta=Dinic_dfs(src,OO) ) ret+=delta; } return ret; } }solver; int thead[maxn]; edgenode tedges[maxm]; int tedge_num; struct OGC{ int u,v,w; }ogc[14]; int cnt; int ww[maxn]; int main() { int n,m; int mincost,maxnum,cost,num; while (~scanf("%d%d",&n,&m)) { cnt=0; solver.prepare(n+2,0,n+1); for (int i=1;i<=n;i++) { scanf("%d",&ww[i]); solver.addedge(solver.src,i,ww[i]); } for (int i=0;i<m;i++) { int u,v,w,p; scanf("%d%d%d%d",&u,&v,&w,&p); if (p<0) { solver.addedge(u,solver.dest,w); solver.addedge(u,v,OO); } if (p>0) { //solver.addedge(u,v,1); ogc[cnt].u=u; ogc[cnt].v=v; ogc[cnt].w=w; cnt++; } if (p==0) { solver.addedge(u,v,OO); } } memcpy(thead,solver.head,sizeof(thead)); memcpy(tedges,solver.edges,sizeof(tedges)); tedge_num=solver.edge; mincost=0; maxnum=0; for (int i=0;i<(1<<cnt);i++) { solver.edge=tedge_num; memcpy(solver.head,thead,sizeof(solver.head)); memcpy(solver.edges,tedges,sizeof(solver.edges)); cost=0; num=0; for (int j=0;j<cnt;j++) { if (i&(1<<j)) { solver.addedge(ogc[j].u,ogc[j].v,OO); cost+=ogc[j].w; } else { solver.addedge(ogc[j].u,ogc[j].v,1); } } num=solver.Dinic_flow(); if (num>maxnum) { maxnum=num; mincost=cost; } else if (num==maxnum&&cost<mincost) { mincost=cost; } } if (maxnum>0) { printf("%d %d\n",maxnum,mincost); } else { puts("Poor Heaven Empire"); } } return 0; } /* #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <set> using namespace std; const int maxn=1111; const int maxm=1111111; const int INF=1e9; struct Edge{ int from,to,cap,flow; }; struct Dinic{ int n,m,s,t; vector<Edge>edges; vector<int>G[maxn]; bool vis[maxn]; int d[maxn]; int cur[maxn]; void init(int n){ this->n=n; for (int i=0;i<n;i++) G[i].clear(); edges.clear(); m=0; } void addedge(int from,int to,int cap){ edges.push_back((Edge){from,to,cap,0}); edges.push_back((Edge){to,from,0,0}); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS(){ memset(vis,0,sizeof(vis)); queue<int>que; que.push(s); d[s]=0; vis[s]=true; while (!que.empty()){ int x=que.front();que.pop(); for (int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if (!vis[e.to]&&e.cap>e.flow){ vis[e.to]=true; d[e.to]=d[x]+1; que.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if (x==t||a==0) return a; int flow=0,f; for (int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if (d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if (a==0) break; } } return flow; } int Maxflow(int s,int t){ this->s=s; this->t=t; int flow=0; while (BFS()){ memset(cur,0,sizeof(cur)); flow+=DFS(s,INF); } return flow; } }solver; vector<Edge>tmpedges; struct OGC{ int u,v,w; }ogc[14]; int cnt; int ww[maxn]; int main() { int n,m; int mincost,maxnum,cost,num; int s,t; while (~scanf("%d%d",&n,&m)) { cnt=0; solver.init(n+2); s=0; t=n+1; for (int i=1;i<=n;i++) { scanf("%d",&ww[i]); solver.addedge(s,i,ww[i]); } for (int i=0;i<m;i++) { int u,v,w,p; scanf("%d%d%d%d",&u,&v,&w,&p); if (p<0) { solver.addedge(u,t,w); solver.addedge(u,v,INF); } if (p>0) { //solver.addedge(u,v,1); ogc[cnt].u=u; ogc[cnt].v=v; ogc[cnt].w=w; cnt++; } if (p==0) { solver.addedge(u,v,INF); } } tmpedges=solver.edges; mincost=0; maxnum=0; for (int i=0;i<(1<<cnt);i++) { solver.edges=tmpedges; cost=0; num=0; for (int j=0;j<cnt;j++) { if (i&(1<<j)) { solver.addedge(ogc[j].u,ogc[j].v,INF); cost+=ogc[j].w; } else { solver.addedge(ogc[j].u,ogc[j].v,1); } } num=solver.Maxflow(s,t); if (num>maxnum) { maxnum=num; mincost=cost; } else if (num==maxnum&&cost<mincost) { mincost=cost; } } if (maxnum>0) { printf("%d %d\n",maxnum,mincost); } else { puts("Poor Heaven Empire"); } } return 0; } */