[最小割] 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 }

 

posted @ 2019-07-30 09:44  BEYang_Z  阅读(215)  评论(0编辑  收藏  举报