返回顶部

The 2020 ICPC Asia Taipei-Hsinchu Site Programming Contest, problem F.Cable Protection (树形dp)

  • 题意:有一颗基环树,求它的最小点覆盖。

  • 题解:先考虑环,对于环上的任意一条边\(u->v\),一定只有2中情况,\(u\)覆盖的情况或\(v\)覆盖的情况。然后不难发现,假如我们将某个点覆盖,那么它的儿子一定不能覆盖,这其实就是树形dp。所以只有对覆盖\(u\)\(v\)的情况分别跑一边树形dp然后取最小即可。

  • 代码

    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <unordered_set>
    #include <unordered_map>
    #define ll long long
    #define db double
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
     
    int n,m;
    int root1,root2;
    vector<int> edge[N];
    ll dp[N][2];
     
    void dfs(int u,int fa,int root){
        for(auto to:edge[u]){
            if(to==fa || to==root) continue;
            dfs(to,u,root);
            dp[u][0]+=dp[to][1];
            dp[u][1]+=min(dp[to][1],dp[to][0]);
        }
        dp[u][1]++;
    }
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n>>m;
        for(int i=1;i<=n+m;++i){
            int u,v;
            cin>>u>>v;
            u++,v++;
            edge[u].pb(v),edge[v].pb(u);
        }
        ll ans;
        dfs(1,n,1);
        ans=dp[1][1];
        me(dp,0,sizeof(dp));
        dfs(n,1,n);
        ans=min(ans,dp[n][1]);
        cout<<ans<<'\n';
        return 0;
    }
    
posted @ 2021-08-29 16:14  Rayotaku  阅读(179)  评论(0编辑  收藏  举报