• 【题解】Luogu P2899 [USACO008JAN] 手机网络 树形dp


    每个点的状态只和他的父亲和儿子有关

    转移方程:

    $f[i][0]$  i放  

    $f[i][1]$  i不放,儿子放

    $f[i][2]$ i不放,父亲放

    j是i的一个儿子

    i放,可以覆盖自己、父亲和儿子。i放的情况下,j可以放或不放

    $f[i][0]+=min(f[j][0],f[j][1],f[j][2])$

    i的父亲放,可以覆盖i的父亲和i。j只能选择自己放或被儿子覆盖

    $f[i][2]++min(f[j][0],f[j][1])$

    从i的儿子中,选一个去覆盖i,其余的按照f[i][2]转移

    $f[i][1]=f[j][0]+{sum}min(f[son][0],f[son[1])$

    优化:

    对于j,有$f[i][1]=f[j][0]+{sum}min(f[son][0],f[son[1])$

    如果j不是最优的,有k满足

    $f[j][0]+{sum}min(f[son][0],f[son[1])<f[k][0]+{sum}min(f[son][0],f[son[1])$

    =>

    $f[j][0]-min(f[son][0],f[son][1])>f[k][0]-min(f[son][1],f[son][0])$

    所以对于最优的j,一定有$f[x][0]-min(f[son][0],f[son][1])$是所有儿子里最小的

    code 

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 namespace gengyf{
     4 #define ll long long
     5 const int maxn=1e4+10;
     6 const int inf=1e9+7;
     7 inline int read(){
     8     int x=0,f=1;
     9     char c=getchar();
    10     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    11     while(c>='0'&&c<='9'){x=(x*10)+c-'0';c=getchar();}
    12     return x*f;
    13 }
    14 struct edge{
    15     int nxt,to;
    16 }e[maxn*2];
    17 int head[maxn],cnt;
    18 int f[maxn][3],n;
    19 inline void add(int from,int to){
    20     e[++cnt].to=to;e[cnt].nxt=head[from];head[from]=cnt;
    21 }
    22 void dfs(int x,int fa){
    23     int son=0;f[x][0]=1;
    24     for(int i=head[x];i;i=e[i].nxt){
    25         int y=e[i].to;
    26         if(y==fa)continue;
    27         dfs(y,x);
    28         f[x][0]+=min(f[y][0],min(f[y][1],f[y][2]));
    29         f[x][2]+=min(f[y][0],f[y][1]);
    30         if((f[son][0]-min(f[son][1],f[son][0]))>(f[y][0]-min(f[y][1],f[y][0]))){
    31             son=y;
    32         }
    33     }
    34     f[x][1]=f[son][0];
    35     for(int i=head[x];i;i=e[i].nxt){
    36         int y=e[i].to;
    37         if(y==fa||son==y)continue;
    38         f[x][1]+=min(f[y][0],f[y][1]);
    39     }
    40 }
    41 int main(){
    42     n=read();
    43     for(int i=1;i<n;i++){
    44         int a,b;
    45         a=read();b=read();
    46         add(a,b);add(b,a);
    47     }
    48     f[0][0]=inf;
    49     dfs(1,-1);
    50     printf("%d",min(f[1][0],f[1][1]));
    51     return 0;
    52 }
    53 }
    54 signed main(){
    55   gengyf::main();
    56   return 0;
    57 }
    View Code

    好几倍经验题

    P2458 P3267 P3942 P2016 P2279...

  • 相关阅读:
    javascript前端如何使用google-protobuf
    【Linux】Linux中常用操作命令
    MyEclipse 安装svn 插件步骤详情
    MultipartFile(文件的上传)--CommonsMultipartResolver
    oracle sql 获取本季度所有月份,上季度所有月份
    git与github安装、配置
    Java使用JaxWsDynamicClientFactory和HttpURLConnection两种方式调取webservice的接口
    三级联动
    Excel的两种导出入门方法(JAVA与JS)
    页面设置遮罩层
  • 原文地址:https://www.cnblogs.com/gengyf/p/11592793.html
Copyright © 2020-2023  润新知