题目描述
监狱有N条道路连接N + 1个交点,编号0至N,整个监狱被这些道路连在一起(任何2点之间都有道路),人们通过道路在交点之间走来走去。其中的一些交点只有一条路连接,这些点是监狱的出口。在各个交点中有M个点住着犯人(M <= N + 1),剩下的点可以安排警卫,有警卫把守的地方犯人无法通过。给出整个监狱的道路情况,以及犯人所在的位置,问至少需要安排多少个警卫,才能保证没有1个犯人能够逃到出口,如果总有犯人能够逃出去,输出-1。
如上图所示,点1,6 住着犯人,0,4,5,7,8是出口,至少需要安排4个警卫。
Input
第1行:2个数N, M中间用空格分隔,N表示道路的数量,M表示犯人的数量(1<= N <= 100000, 0 <= M <= N + 1)。 之后N行:每行2个数S, E中间用空格分隔,表示点编号为S的点同编号为E的点之间有道路相连。(0 <= S, E <= N)。 之后的M行,每行1个数Pi,表示编号为Pi的点上有犯人。
Output
输出1个数对应最少需要多少警卫才能不让犯人逃出监狱。
Input示例
8 2 0 1 1 2 2 3 3 4 3 5 2 6 6 8 6 7 1 6
Output示例
4
Solution
典型的一道树形dp,听说有人跑20万网络流过了Orz
使得任意一个出口为根节点,逃离方向就固定为向上到根或向下到叶子节点
考虑一个点的3种状态:
f[i],表示以i为根的子树的状态
f[i]=0,子树中的点无法到达这个点,且不存在一条从这点到叶子节点的路径。
f[i]=1,子树中的点无法到达这个点,但存在一条从这点到叶子节点的路径。
f[i]=2,子树中的点可以到达这个点,且不存在一条从这点到叶子节点的路径
i点的儿子的状态都为0,则f[i]=0
儿子的状态有1也有2,则i点必须放,ans++(以为2点可以通过i点到叶子节点)
若i有逃犯则儿子中有1状态的都要被放,ans加上儿子为1的个数
剩下的儿子状态单一,直接转移即可。
Code
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #define fo(i,a,b) for(int i=a;i<=b;i++) 6 #define fd(i,a,b) for(int i=a;i>=b;i--) 7 #define fh(i,x) for(int i=head[x];i;i=next[i]) 8 typedef long long LL; 9 using namespace std; 10 inline int max(int x,int y) {return (x<y)?y:x;} 11 inline int min(int x,int y) {return (x<y)?x:y;} 12 inline int read() { 13 int x=0,f=1;char ch=getchar(); 14 while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar(); 15 while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x; 16 } 17 const int N=1e5+5; 18 int n,m,tot,x,y,ans,d[N],f[N]; 19 int to[N*2],next[N*2],head[N]; 20 bool bz[N]; 21 void add(int x,int y) {to[++tot]=y;next[tot]=head[x];head[x]=tot;} 22 void dfs(int x,int y) { 23 int s[3];memset(s,0,sizeof(s)); 24 fh(i,x) if(to[i]!=y) dfs(to[i],x),s[f[to[i]]]++; 25 if (bz[x]) ans+=s[1],f[x]=2; 26 else if(s[1]&&s[2]) ans++,f[x]=0; 27 else if(s[1]) f[x]=1; 28 else if(s[2]) f[x]=2; 29 else if(s[0]) f[x]=0; 30 } 31 int main() { 32 n=read(),m=read(),n++; 33 fo(i,1,n-1) x=read(),y=read(),x++,y++,add(x,y),add(y,x),d[x]++,d[y]++; 34 fo(i,1,n) f[i]=1; 35 fo(i,1,m) { 36 x=read(),x++; 37 if(d[x]==1) {printf("-1 ");return 0;} 38 bz[x]=1; 39 } 40 int root=1; 41 fo(i,1,n) if(d[i]==1) {root=i;break;} 42 dfs(root,0); 43 if(f[root]==2) ans++; 44 printf("%d ",ans); 45 }