1.牛客小白月赛45-E第一道接触的树上dp.
题意:给定你一个n个节点的树,你需要在树上选取一个非空连通块,使其舒适度和最大。选择的边和点的舒适度都是舒适度。
代码:
void dfs(int now,int fa){
dp[now]=a[now];
for(int i=h[now];~i;i=nx[i]){
int to=e[i];
if(to==fa)continue;
int w=value[i];
dfs(to,now);
if(w+dp[to]>0)dp[now]+=w+dp[to];
}
}
2.牛客小白月赛48-孤独的树
题意:给定一个n个节点的树,每个节点有一个权值,定义孤独的树为任意两个节点的gcd==1,每次操作可以将一个节点除以x,问最小进行多少次操作。
思路:贪心在下面的节点无论如何都要与上面的节点gcd==1,则将他的父节点除以他们的gcd,将更好的机会留给了上面的节点。注意用筛法预处理出每个数的质因子个数。
代码:
//预处理2-N中每个数的质因子数
void init(){
for(int i=2;i<=N;i++){
if(!cnt[i]){
cnt[i]=1;
//将带有i因子的数加上因子有该因子数的个数数
for(int j=i+i;j<=N;j+=i){
int t=j;
while(t%i==0)cnt[j]++,t/=i;
}
}
}
}
//dp方程
void dfs(int u,int fa){
for(int i=0;i<v[u].size();i++){
int to=v[u][i];
if(to==fa)continue;
dfs(to,u);
int g=gcd(val[u],val[to]);
ans+=cnt[g];
val[u]/=g;
}
}
3.codeforces gdut排位赛
题意:给定你一颗树,每个节点可以是黑色或者白色,可以进行两种操作。操作一:将一个节点的颜色改为相反的颜色。操作二:将相同颜色的一个连通块消除。
问最少操作次数能将所有节点消除。
思路:对于任意一个节点有黑色和白色的选择,我们开一个大小为[n][2]的树组,j表示该节点的颜色,然后进行dfs.
状态转移方程为:
//颜色相同则减掉上一步消去的步骤,颜色不相同则直接加上去即可
dp[s[u]-'0'][u]+=min(dp[s[u]-'0'][to]-1,dp[!(s[u]-'0')][to]);
dp[!(s[u]-'0')][u]+=min(dp[!(s[u]-'0')][to]-1,dp[s[u]-'0'][to]);
代码:
void dfs(int u,int fa)
{
dp[s[u]-'0'][u]=1;//直接消去
dp[!(s[u]-'0')][u]=2;//先变颜色再消去
for(int i=h[u];~i;i=nx[i]){
int to=e[i];
if(to==fa) continue;
dfs(to,u);
//颜色相同则减掉上一步消去的步骤,颜色不相同则直接加上去即可
dp[s[u]-'0'][u]+=min(dp[s[u]-'0'][to]-1,dp[!(s[u]-'0')][to]);
dp[!(s[u]-'0')][u]+=min(dp[!(s[u]-'0')][to]-1,dp[s[u]-'0'][to]);
}
}
4.cf div3 786 G. Remove Directed Edges
题意:给定一个有向无环图,要求你找到最长的一条路径,且这条路径上的所有节点的出边和入边都至少为2(除了出发点入边可以等于1或者0,结束点出边可以等于1或者0)
思路:直接树形dp即可,找出最长的链。
代码:
int dp[N]={0},in[N],out[N];
vector<int> v[N];
void dfs(int u){
if(dp[u])return;
dp[u]=1;
if(out[u]<=1)return;
for(int i=0;i<v[u].size();i++){
int to=v[u][i];
dfs(to);
if(in[to]>=2)dp[u]=max(dp[u],dp[to]+1);
}
}