zoukankan      html  css  js  c++  java
  • Codeforces 219D

    题目链接:https://vjudge.net/problem/CodeForces-219D

    首先,类似于网上大部分题解所说的,设某一条边正向的weight=0,反向的weight=1,因为反向意味着我们(按DFS方向)走到这条边的时候,就得把这条边翻转,就相当于记一次(w=1)。

    然后同样的,

    dp[i][0]:表示以i为root的子树中,我们从i出发,要翻转(inverse)多少条边。

    dp[i][1]:表示从i往其父亲方向走,要翻转(inverse)多少条边。

    那么,最后我们要的,当一个点i为capital时,就要翻转dp[i][0]+dp[i][1]条边。

    类似于HDU2196(http://www.cnblogs.com/dilthey/p/7186556.html),我们也要分两次做DFS,第一次做出所有的dp[i][0],第二次做出所有的dp[i][1];

    状态转移方程:

    对于某个节点u,有子节点(直接相连的)v1~vk,则

    dp[u][0] = ( edge[u][v1].w + dp[v1][0] ) + …… + ( edge[u][vk].w + dp[vk][0] )

    对于某个节点v,有父亲节点u,则

    dp[v][1] = dp[u][1] + ( dp[u][0] - ( edge[u][v].w + dp[v][0] )  ) + ( (edge[u][v].w==1) ? 0 : 1 )

    (这个状态转移方程画个图就比较好想,一个节点往上走,可以是它的父亲节点再往上走,也可以是它的父亲节点的其他孩子树,再包括它和它父亲节点相连的那条边)

    所以,代码如下:

     1 #include<cstdio>
     2 #include<vector>
     3 #define MAXN 200000+5
     4 using namespace std;
     5 int n,dp[MAXN][2];
     6 struct Edge{
     7     int u,v,w;
     8 };
     9 vector<Edge> adj[MAXN];
    10 void dfs1(int now,int par)
    11 {
    12     if(adj[now].empty())
    13     {
    14         dp[now][0]=0;
    15         return;
    16     }
    17     for(int i=0;i<adj[now].size();i++)
    18     {
    19         Edge edge=adj[now][i];
    20         int next=edge.v;
    21         if(next==par) continue;
    22         dfs1(next,now);
    23         dp[now][0]+=edge.w+dp[next][0];
    24     }
    25 }
    26 void dfs2(int now,int par)
    27 {
    28     if(now==1) dp[now][1]=0;
    29     for(int i=0;i<adj[now].size();i++)
    30     {
    31         Edge edge=adj[now][i];
    32         int next=edge.v;
    33         if(next==par) continue;
    34         dp[next][1] = dp[now][1] + ( dp[now][0] - (edge.w+dp[next][0]) ) + (edge.w?0:1);
    35         dfs2(next,now);
    36     }
    37 }
    38 int main()
    39 {
    40     scanf("%d",&n);
    41     for(int i=1;i<n;i++)
    42     {
    43         int from,to;
    44         scanf("%d%d",&from,&to);
    45         adj[from].push_back((Edge){from,to,0});
    46         adj[to].push_back((Edge){to,from,1});
    47     }
    48     dfs1(1,0);
    49     dfs2(1,0);
    50     vector<int> ans;
    51     int min=dp[1][0]+dp[1][1];
    52     for(int i=1;i<=n;i++)
    53     {
    54         if(min>dp[i][0]+dp[i][1])
    55         {
    56             min=dp[i][0]+dp[i][1];
    57             ans.clear();
    58         }
    59         if(min==dp[i][0]+dp[i][1])
    60         {
    61             ans.push_back(i);
    62         }
    63     }
    64     printf("%d
    ",min);
    65     for(int i=0;i<ans.size();i++)
    66     {
    67         if(i!=0) printf(" ");
    68         printf("%d",ans[i]);
    69     }
    70     printf("
    ");
    71 }

    可以说是第一道大部分都是自己独立完成的树形DP,还是值得庆祝一下的~

  • 相关阅读:
    SignalR实现服务器与客户端的实时通信
    UIWebView全解
    查漏补缺
    Django的生命周期图解
    权限系统(第一次测试)
    Django权限管理测试
    Django_自带的admin管理页面
    django笔记整理
    cookie/session(过时的写法)
    图书管理系统设置登录验证(cookies)
  • 原文地址:https://www.cnblogs.com/dilthey/p/7192498.html
Copyright © 2011-2022 走看看