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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮