[最小割] Luogu P4662 黑手党
题目描述
Byteland 国警方收到了一条匿名举报,其中说当地黑帮老大正计划一次从港口到郊区仓库的运输。警方知道运输的时间并且知道运输需要用到国家的高速公路网。
高速公路网包含双向的高速公路段,每个路段直接连着两个不同的收费站。一个收费站可能与很多其他的收费站相连。汽车只能通过收费站进入或离开高速公路网。据所知,黑帮会距港口边最近的收费站进入高速公路,从距仓库最近的收费站离开(不会在出高速后重新进入)。特警组位于选定的收费站处。当运输车辆进入被监控的收费站时,它就会被警察抓住。
从这个角度看,最简单的办法就是在每个收费站处都安排特警班。然而,控制一个收费站需要特定的费用,每个收费站费用不同。警方想要让花费最小,所以他们需要制定一个收费站的最小控制集,这个集合满足两个条件:
- 所有从港口到仓库的交通必须至少经过集合中的一个收费站
- 监控这些收费站的费用(即监控每一个收费站费用之和)最小
你可以假设使用高速公路可以从港口到仓库。
#任务
写一个程序能够:
- 从标准输入中读取高速公路网,监控代价和运输的起点和终点
- 找到收费站的最小控制集
- 输出这个集合到标准输出
题解
- 这题就是个裸的最小割,将一个点拆成i和i+n,两点之间连一条边为费用,如果被割了就是被监视了
- 那么怎么输出方案呢?
- 只用在残余网络上dfs一下,看两点之间所属点集是否相同就好了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <vector> 5 #include <queue> 6 #include <algorithm> 7 using namespace std; 8 const int N=4e2+10,M=1e5+10,inf=1<<30; 9 int n,m,s,t,sz,cnt=1,head[N],state[N],cur[N]; 10 bool vis[N]; 11 vector<int>ans; 12 struct edge {int to,from,w;}e[M]; 13 void insert(int x,int y,int v) 14 { 15 e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].w=v; 16 e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].w=0; 17 } 18 int bfs(int s,int t) 19 { 20 memset(state,0,sizeof(state)),memcpy(cur,head,sizeof(head)); 21 queue<int>Q; while (!Q.empty()) Q.pop(); 22 Q.push(s),state[s]=1; 23 while (!Q.empty()) 24 { 25 int x=Q.front(); Q.pop(); 26 for (int i=head[x];i;i=e[i].from) if (e[i].w&&!state[e[i].to]) Q.push(e[i].to),state[e[i].to]=state[x]+1; 27 } 28 return state[t]; 29 } 30 int dfs(int x,int y,int flow) 31 { 32 if (x==y) return flow; 33 int f=0,r; 34 for (int i=cur[x];i&&f<flow;i=e[i].from) 35 { 36 cur[x]=i; 37 if (e[i].w&&state[e[i].to]==state[x]+1) r=dfs(e[i].to,y,min(e[i].w,flow-f)),e[i].w-=r,e[i^1].w+=r,f+=r; 38 } 39 if (f<flow) state[x]=-1; 40 return f; 41 } 42 void dinic(int s,int t) { while (bfs(s,t)) while (dfs(s,t,inf)); } 43 void dfs(int x) { vis[x]=1; for (int i=head[x];i;i=e[i].from) if (e[i].w&&!vis[e[i].to]) dfs(e[i].to); } 44 int main() 45 { 46 scanf("%d%d%d%d",&n,&m,&s,&t); 47 for (int i=1,x;i<=n;i++) scanf("%d",&x),insert(i,i+n,x); 48 for (int x,y;m;m--) scanf("%d%d",&x,&y),insert(x+n,y,inf),insert(y+n,x,inf); 49 dinic(s,t+n),dfs(s); 50 for (int i=2;i<=cnt;i+=2) if (vis[e[i^1].to]&&!vis[e[i].to]) ans.push_back(e[i^1].to); 51 sort(ans.begin(),ans.end()),sz=ans.size()-1; 52 for (int i=0;i<=sz;i++) printf("%d ",ans[i]); 53 }