• [UVA-1218] Perfect Service(树的最小支配集)


    题目链接:https://vjudge.net/problem/UVA-1218

    题目大意:给你一棵无向树,让你求树的最小支配集,但是有一个要求是除最小支配集外剩下的任何一个结点不能同时连接支配集中的两个元素

    解题报告:采用树形dp,只需将第一种状态的状态转移方程修改为$dp[i][0] = 1+sum_{ p[u]=i }min(dp[u][0],dp[u][2])$

    AC代码:

     1 #include<vector>
     2 #include<cstdio>
     3 #include<iostream>
     4 #include<cmath>
     5 #include<queue>
     6 #include<stack>
     7 #define numm ch-48
     8 #define pd putchar(' ')
     9 #define pn putchar('
    ')
    10 #define pb push_back
    11 #define fi first
    12 #define se second
    13 #define fre1 freopen("1.txt","r",stdin)
    14 #define fre2 freopen("2.txt","w",stdout)
    15 using namespace std;
    16 template <typename T>
    17 void read(T &res) {
    18     bool flag=false;char ch;
    19     while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
    20     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
    21     flag&&(res=-res);
    22 }
    23 template <typename T>
    24 void write(T x) {
    25     if(x<0) putchar('-'),x=-x;
    26     if(x>9) write(x/10);
    27     putchar(x%10+'0');
    28 }
    29 const int maxn=10010;
    30 const int N=1010;
    31 const int inf=0x3f3f3f3f;
    32 const int INF=0x7fffffff;
    33 typedef long long ll;
    34 struct node {
    35     int v,net;
    36 }e[maxn<<1];
    37 int cnt,n,head[maxn];
    38 int dp[maxn][3];
    39 void add(int u,int v) {
    40     e[++cnt].v=v;
    41     e[cnt].net=head[u];
    42     head[u]=cnt;
    43 }
    44 void DP(int u,int p) {  ///u:当前结点,p:u的父结点
    45     bool flag=false;    ///标记是否有一个dp[to][0]<=dp[to][1]
    46     int sum=0,inc=INF;
    47     dp[u][2]=0; ///第三状态,当前结点未被选中
    48     dp[u][0]=1; ///第一状态,当前结点被选中,dp[u][0]+1
    49     for(int i=head[u];i!=-1;i=e[i].net) {
    50         int to=e[i].v;
    51         if(to==p) continue; ///to必须是u的子节点,不是父节点(由根dp到叶子)
    52         DP(to,u);   ///dp子节点
    53         dp[u][0]+=min(dp[to][0],dp[to][2]);  ///回溯,第一状态的转移
    54         if(dp[to][0]<=dp[to][1]) {  ///第二状态的判断
    55             flag=true;
    56             sum+=dp[to][0];
    57         }
    58         else {
    59             sum+=dp[to][1];
    60             inc=min(inc,dp[to][0]-dp[to][1]);
    61         }
    62         if(dp[to][1]!=INF&&dp[u][2]!=INF)    ///第三状态的转移
    63             dp[u][2]+=dp[to][1];
    64         else dp[u][2]=INF;  ///根据定义dp[u][2]=(dp[to][1]的总和)
    65     }
    66     if(!flag&&inc==INF) ///判断当前是不是叶子结点
    67         dp[u][1]=INF;
    68     else
    69         dp[u][1]=sum+(flag?0:inc);
    70 }
    71 int main()
    72 {
    73     while(scanf("%d",&n)!=EOF&&n) {
    74         for(int i=1;i<=n;i++)
    75             head[i]=-1,dp[i][0]=dp[i][1]=dp[i][2]=0,cnt=0;
    76         for(int i=1;i<=n-1;i++) {
    77             int a,b;
    78             read(a),read(b);
    79             add(a,b);
    80             add(b,a);
    81         }
    82         DP(1,1);
    83         write(min(dp[1][0],dp[1][1]));pn;
    84         int flag;
    85         read(flag);
    86         if(flag==-1) break;
    87     }
    88     return 0;
    89 }
    代码在这里!

  • 相关阅读:
    gitlab web端使用
    1、gitlab的理论知识
    git命令
    gitlab web客户端的使用
    jenkins
    jenkins pipeline
    nginx
    ELK(+Redis)-开源实时日志分析平台
    OpenStack构架知识梳理
    Linux 下的dd命令使用详解
  • 原文地址:https://www.cnblogs.com/wuliking/p/11264374.html
Copyright © 2020-2023  润新知