树形DP
P2607 [ZJOI2008] 骑士
每个骑士只有一个讨厌的人,所以反向建图后,就变成了每个点只有一条入边的外向树;
然后找环,拆环,因为环上的相邻两点只能选一个,所以我们需要强制其中一个不选;
答案为环上的点的最大值的和;
//和树形DP模板题【上司的舞会】很相似
AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+5;
const int inf=0x3f3f3f3f;
ll n,a[N];
inline ll read()
{
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
//建图
ll h[N],ver[N*2],nex[N*2],tot=0;
void add(int u,int v)
{
ver[++tot]=v,nex[tot]=h[u],h[u]=tot;
}
int fa[N],hate[N],root,rt;
ll f[N][2];//f[i][0]不选i,f[i][1]选i
int find(int x)
{
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void dfs(int x)//dp
{
f[x][1]=a[x],f[x][0]=0;
if(rt==x)f[x][1]=-inf;
for(int i=h[x];i;i=nex[i])
{
int v=ver[i];
if(v==root)continue;
dfs(v);
if(x==rt)f[x][0]+=max(f[v][0],f[v][1]);
else
{
f[x][0]+=max(f[v][0],f[v][1]);
f[x][1]+=f[v][0];
}
}
}
void solve()
{
long long ans=0;
for(int i=1;i<=n;i++)
{
if(find(i)==i)//拆环,单一的树
{
root=i;
rt=hate[i];
dfs(i);//强制不选hate[i]
ll t=max(f[i][1],f[i][0]);
rt=i;
dfs(i);//强制不选i
ans+=max(t,f[i][0]);
}
}
cout<<ans<<endl;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=n;i++)
{
a[i]=read();hate[i]=read();//只有一条入边(反向建图)
add(hate[i],i);fa[i]=find(hate[i]);//外向树
}
solve();
return 0;
}
P3621 [APIO2007] 风铃
这道题只有树形,没有dp,用dfs判断一下就好了,但是有很多细节;
-
先dfs一遍,记录玩具到根节点的最小距离和最远距离,如果差值大于1,不满足条件1,输出-1;
-
再dfs一遍,如果左子树最大值大于右子树最大值,交换左子树和右子树,ans++;
-
交换完了之后判断是否符合条件2,如果不符合结束dfs,输出-1,否则继续dfs;
-
最后输出ans;
AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
inline ll read()
{
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int n;
struct ww{
int l,r;
int mx,mi;
}pl[N];
int fa[N];
int find(int x)
{
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
int d[N],ans=0;
void dfs(int x)
{
if(x==-1)
{
pl[x].mi=pl[x].mx=1;
return ;
}
dfs(pl[x].l);dfs(pl[x].r);
pl[x].mx=max(pl[pl[x].l].mx,pl[pl[x].r].mx)+1;
pl[x].mi=min(pl[pl[x].l].mi,pl[pl[x].r].mi)+1;
}
bool check(int x)
{
if(x==-1)return true;
if(check(pl[x].l)==0||check(pl[x].r)==0)return false;
if(pl[pl[x].l].mx<pl[pl[x].r].mx)
{
swap(pl[x].l,pl[x].r);
ans++;
}
if(pl[pl[x].l].mx==pl[pl[x].r].mx)
{
if(pl[pl[x].l].mi==pl[pl[x].r].mx)
{
return true;
}
else if(pl[pl[x].r].mi==pl[pl[x].r].mx)
{
swap(pl[x].l,pl[x].r);
ans++;
return true;
}
else return false;
}
if(pl[pl[x].l].mi<pl[pl[x].r].mx)return false;
return true;
}
void solve()
{
for(int i=1;i<=n;i++)
{
if(find(i)==i)
{
dfs(i);
if(pl[i].mx>pl[i].mi+1)
{
printf("-1");
}
else if(check(i))
{
printf("%d",ans);
}
else printf("-1");
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=n;i++)
{
pl[i].l=read(),pl[i].r=read();
if(pl[i].l!=-1)fa[pl[i].l]=find(i);
if(pl[i].r!=-1)fa[pl[i].r]=find(i);
}
solve();
return 0;
}

浙公网安备 33010602011771号