[51nod1299]监狱逃离
来源:互联网 发布:淘宝双十一交易额2014 编辑:程序博客网 时间:2024/05/03 14:37
Description
给出一个n+1个点n条边的树,其中每一个度数为1的点为出口。
现在有一些点有逃犯,你需要在一些没有逃犯的点放置警卫,有警卫的点逃犯无法经过。
求若使所有逃犯均无法到达出口,最少需要多少个警卫。
n<=10^5
Solution
为什么我一眼想到最小割=w=
就是所有的逃犯无法到达一些点,那么我们把每个点拆点,x向x’连容量为1的边,割掉这条边表示在这个点放置警卫。
然后对于原图中的每一条边(x,y),从x’向y连容量为∞的边,表示这条边无法被割掉。
同理从S向每个有逃犯的x’点连容量为∞的边,因为无法在有逃犯的点放置警卫。
然后从每个出口的x’点向T连容量为∞的边,因为可以在出口放置警卫。
然后跑一边最小割就是答案了。如果最小割为∞就是无解。
200000个点的最大流什么的真是梦想_ (:зゝ∠)_
然而它碾过去了2333
好吧我们来讨论正解=w=
随便选一个度数为1的点做根节点,那么所有的出口都是根节点或者叶子节点了。
考虑从下往上递推,每个点可以有三种情况
0:这个点为根的子树中所有的逃犯都无法到达这个点,且不存在一条从这点到叶子节点的路径。
1:这个点为根的子树中所有的逃犯都无法到达这个点,但存在一条从这点到叶子节点的路径。
2:这个点为根的子树中所有的逃犯有可能到达这个点,且不存在一条从这点到叶子节点的路径。
那么考虑一个点,如果它的所有儿子都被封死了(就是状态0),那么它自己也就被封死了。
如果这个点有逃犯,那么这个点一下的1点都必须被封死,要不然逃犯可以通过这个点到叶子节点,所以答案加上当前节点状态为1的儿子个数。
否则如果当前点既有状态为1的儿子,又有状态为2的儿子,那么2的逃犯就可以到达这个点,然后从这个点往下逃走。
所以这个点必须被封死。
否则就是只有0\1,0\2的情况,那么除0外是几这个点的状态就是几。
最后如果根节点的状态为2根节点也要封死。
Code
最小割
#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define rep(i,a) for(int i=last[a];i;i=next[i])using namespace std;const int N=2*1e5+5,inf=1e5;int n,m,S,T,l,x,y,ans,dis[N],d[N],r[N];int t[N*8],next[N*8],f[N*8],last[N];void add(int x,int y,int z) { t[++l]=y;f[l]=z;next[l]=last[x];last[x]=l; t[++l]=x;f[l]=0;next[l]=last[y];last[y]=l;}bool bfs() { memset(dis,0,sizeof(dis));dis[S]=1; int i=0,j=1;d[1]=S; while (i<j) rep(k,d[++i]) if (!dis[t[k]]&&f[k]) dis[t[k]]=dis[d[i]]+1,d[++j]=t[k]; return dis[T];}int dinic(int x,int y) { if (x==T) return y; int now=0; rep(i,x) if (f[i]&&dis[t[i]]==dis[x]+1) { int k=dinic(t[i],min(y,f[i])); y-=k;now+=k;f[i]-=k;f[i^1]+=k; if (!y) break; } if (!now) dis[x]=-1; return now;}int main() { scanf("%d%d",&n,&m);n++;S=0;T=2*n+1;l=1; fo(i,1,n-1) { scanf("%d%d",&x,&y);x++;y++; add(x+n,y,inf);add(y+n,x,inf); r[x]++;r[y]++; } fo(i,1,m) scanf("%d",&x),x++,add(S,x+n,inf); fo(i,1,n) if (r[i]==1) add(i+n,T,inf); fo(i,1,n) add(i,i+n,1); while (bfs()) ans+=dinic(S,inf); if (ans>=inf) printf("-1\n"); else printf("%d\n",ans);}
Dp
#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define rep(i,a) for(int i=last[a];i;i=next[i])using namespace std;const int N=1e5+5;int n,m,l,x,y,ans,d[N],f[N];int t[N*2],next[N*2],last[N];bool bz[N];void add(int x,int y) { t[++l]=y;next[l]=last[x];last[x]=l;}void dfs(int x,int y) { int s[3];memset(s,0,sizeof(s)); rep(i,x) if (t[i]!=y) { dfs(t[i],x); s[f[t[i]]]++; } if (bz[x]) { ans+=s[1]; f[x]=2; } else if (s[1]&&s[2]) { ans++; f[x]=0; } else if (s[1]) f[x]=1; else if (s[2]) f[x]=2; else if (s[0]) f[x]=0;}int main() { scanf("%d%d",&n,&m);n++; fo(i,1,n-1) { scanf("%d%d",&x,&y),x++,y++; add(x,y),add(y,x); d[x]++;d[y]++; } fo(i,1,n) f[i]=1; fo(i,1,m) { scanf("%d",&x),x++; if (d[x]==1) {printf("-1\n");return 0;} bz[x]=1; } fo(i,1,n) if (d[i]==1) { dfs(i,0); if (f[i]==2) ans++; break; } printf("%d\n",ans);}
- [51nod1299]监狱逃离
- 51nod1299 监狱逃离 最小割
- 监狱逃离 51nod1299 最小割
- [51nod1299]监狱逃离 树形DP || 20w个点的网络流最小割ORZ
- 51Nod-1299-监狱逃离
- 51nod 1299 监狱逃离
- 51nod 1299 监狱逃离
- 51nod-1299 监狱逃离(贪心)
- 51nod 1299 监狱逃离 树形DP
- 51nod 1299 监狱逃离 树形dp
- 51nod1299
- 51nod 1299 监狱逃离 树形dp/最小割
- 监狱
- 逃离
- 逃离
- 逃离
- 智能监狱
- 集市与监狱
- 2016.12.20 今天公司出的事
- Android打开WLAN开关的广播状态监听
- ubuntu操作系统中如何获取权限
- ADB命令使用技巧
- Qt-Matlab-Opencv配置小记
- [51nod1299]监狱逃离
- 蓝桥杯BASIC-19(完美的代价)
- Android电量和插拔电源状态广播监听
- 从C++到Java(一)
- MyBatis介绍和入门一
- L04JavaScript基础教程2
- 优达学城 深度学习 任务1
- ACM计算几何题目推荐
- React实战-javascript访问服务端数据大全