监狱逃离 51nod1299 最小割
2017-12-08 19:53
232 查看
题目大意
监狱有N条道路连接N + 1个交点,编号0至N,整个监狱被这些道路连在一起(任何2点之间都有道路),人们通过道路在交点之间走来走去。其中的一些交点只有一条路连接,这些点是监狱的出口。在各个交点中有M个点住着犯人(M <= N + 1),剩下的点可以安排警卫,有警卫把守的地方犯人无法通过。给出整个监狱的道路情况,以及犯人所在的位置,问至少需要安排多少个警卫,才能保证没有1个犯人能够逃到出口,如果总有犯人能够逃出去,输出-1。分析
在olahiuj的安利下做了这题。正解应该是树形dp之类的东东。。。
但是我们也可以用最小割写。。。(不知为何10^5的数据dinic居然能过)
建图:
1.如果i和j有边相连(i,j’,∞)(j,i’,∞)
2.如果i有犯人(s,i,∞)
3.如果i是出口(i,t,∞)
4.把i点拆成入点和出点(i’,i,1)
code
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> using namespace std; struct arr{ int x,y,w,next; }edge[2000000]; int ls[410000],cur[410000]; int f[2100000]; int edge_m=1; int n,m,s,t; int ans,num=0; void add(int x,int y,int w) { edge[++edge_m]=(arr){x,y,w,ls[x]}; cur[y]=ls[x]=edge_m; f[edge_m]=w; edge[++edge_m]=(arr){y,x,w,ls[y]}; cur[y]=ls[y]=edge_m; f[edge_m]=0; } int dis[400000]; bool bfs() { memset(dis,-1,sizeof(dis)); queue<int> q; q.push(s); dis[s]=0; do{ int x=q.front(); q.pop(); for (int i=ls[x];i!=0;i=edge[i].next) { if ((f[i])&&(dis[edge[i].y]==-1)) { dis[edge[i].y]=dis[x]+1; q.push(edge[i].y); if (edge[i].y==t) return true; } } }while (!q.empty()); return false; } int find(int x,int min_) { if (x==t) return min_; int rec=min_; for (int &i=cur[x];i!=0;i=edge[i].next) { if ((f[i])&&(dis[edge[i].y]==dis[x]+1)) { int k=find(edge[i].y,min(min_,f[i])); f[i]-=k; f[i^1]+=k; rec-=k; if (rec==0) return min_; } } if (rec==min_) dis[x]=-1; return min_-rec; } int dinic() { ans=0; while (bfs()) { for (int i=0;i<=t;i++) cur[i]=ls[i]; ans+=find(s,20000000); } } int a[410000]; int du[410000]; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); du[x]++; du[y]++; add(x,y+n+1,410000); add(y,x+n+1,410000); } for (int i=1;i<=m;i++) { int x; scanf("%d",&x); a[x]=1; } n++; s=n*2+1; t=n*2+2; for (int i=0;i<=n;i++) { if (a[i]) add(s,i,410000); else add(i+n,i,1); if (du[i]==1) add(i,t,410000); } dinic(); if (ans==410000) printf("-1"); else printf("%d",ans); }
相关文章推荐
- 51nod 1299 监狱逃离 树形dp/最小割
- [51nod1299] 监狱逃离(最小点覆盖)
- 51nod1299 监狱逃离 最小割
- [51nod1065]最小正子段和
- 51 nod 1065 最小正子段和 排序大法好
- [51nod1238]最小公倍数之和
- 51 nod 1255 字典序最小的子序列(单调栈 贪心)
- 51Nod-1283-最小周长
- 51 nod 1283 最小周长
- 最小正子段和 51Nod - 1065
- 51nod1110 距离之和最小 V3
- 最大子段和(51Nod 1049)、最小正子段和(51Nod 1065)、总结(最小子段和、最大子段和、最小正子段和)
- 51单片机最小系统
- 51Nod-1283-最小周长
- 51 nod 1363 最小公倍数之和
- 自己第一个PCB板(51最小系统)总结
- 51 nod 1255 字典序最小的子序列
- 51nod-1299 监狱逃离(贪心)
- 51 nod 1222 最小公倍数计数
- (51nod)1283 - 最小周长