标签:题目 pre queue net 最小 转移 efi scan long
https://ac.nowcoder.com/acm/problem/24953
题目描述:给出一棵树,选最小的点把所以边覆盖。
思路:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<sstream> #include<vector> #include<stack> #include<deque> #include<cmath> #include<map> #include<queue> #include<bitset> #define sd(x) scanf("%d",&x) #define lsd(x) scanf("%lld",&x) #define ms(x,y) memset(x,y,sizeof x) #define fu(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) #define all(a) a.begin(),a.end() #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; typedef long long ll; typedef unsigned long long ull; typedef long double ld; const int maxn=1e5+79; const int mod=998244353; const ll INF=0x7f7f7f7f; const double pi=acos(-1); ll dp[maxn][3]; vector<int> son[maxn]; int n,k; void dfs(int u,int fa) { //初始化 dp[u][0]=1;dp[u][1]=0;dp[u][2]=0; ll cost=INF; bool find=0; for(int v:son[u]) { if(v==fa) continue; dfs(v,u); //dp:0-选点i //1-不选,i被儿子覆盖 //2-不选,i没有被儿子覆盖 dp[u][0]+=min(min(dp[v][0],dp[v][1]),dp[v][2]); dp[u][2]+=dp[v][1]; //到1的状态,儿子中至少选一个dp[v][0] //找不到就找一个dp[v][1]把他变成dp[v][0],使变化花费最小 if(dp[v][0]<=dp[v][1]) { find=1; dp[u][1]+=dp[v][0]; } else { dp[u][1]+=dp[v][1]; cost=min(cost,dp[v][0]-dp[v][1]); } } //找不到就花最小的代价使得其中一个变 if(!find) dp[u][1]+=cost; } int main() { sd(n); fu(i,1,n-1) { int u,v,w;sd(u);sd(v); son[u].push_back(v); son[v].push_back(u); } dfs(1,0); //根节点就是答案,根节点必须被自己或儿子覆盖 printf("%lld\n",min(dp[1][0],dp[1][1])); return 0; }
Cell Phone Network (树形dp,最小点覆盖)
标签:题目 pre queue net 最小 转移 efi scan long
原文地址:https://www.cnblogs.com/studyshare777/p/13472868.html