• 51nod 1299 监狱逃离


    题目描述

    监狱有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 }
  • 相关阅读:
    JAVA面试题 启动线程是start()还是run()?为什么?
    Java面试题 equals()与"=="的区别?
    Java面试题之数据库三范式是什么?
    很全的Python 面试题 github
    链家二手房 爬虫
    15个重要Python面试题 测测你适不适合做Python?
    静态链接和动态链接
    Python里的拷贝
    GIL线程全局锁 协程
    Python中的作用域
  • 原文地址:https://www.cnblogs.com/patricksu/p/7923104.html
Copyright © 2020-2023  润新知