算法竞赛——进阶指南——acwng359. 创世纪 基环树+树形背包dp +环形dp

一个元素选,则限制其的元素必须至少一个不选。

所以我们把元素指向限制其的元素。建出图。

假如是棵树,则用树形dp即可。(类比经典树形dp舞池问题)

但这是一颗基环树(即最多一个环,因为每个点有且只有一个入边,且是n个点,n条边)

先找到每个联通块的唯一环。

然后把环断开,当成一棵树进行树形dp。

再考虑断开环的影响:比如断开x->y,  影响是:缺少了一条边x->y,  即x选,y不选的情况。那么我们让y固定不选,则x就可以选,且y其他儿子可任意选或不选。

加个flag标记判断跑2次树形dp即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 1e6+7;

int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}

int a[M],vs[M];
int rt;
bool f;
int dp[M][2];//以i为根的子树,i点投放/不投放,  最多投放元素个数 
int fat[M];
void gao(int x)
{
//	cout<<" ----             "<<x<<"  "<<fat[x]<<endl;
	int tp=-1e7;
	vs[x]=1;
	dp[x][0]=dp[x][1]=0;
	for(int i=head[x];i;i=ee[i].nxt)
	{
		int y=ee[i].to;
		if(y==rt)continue;
		gao(y);
		dp[x][0]+=max(dp[y][0],dp[y][1]);
		dp[x][1]+=max(dp[y][0],dp[y][1]);
		tp=max(tp,dp[y][0]-max(dp[y][0],dp[y][1]));
	}
	if(f&&x==fat[rt])dp[x][1]++;
	else dp[x][1]=dp[x][1]+tp+1;
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n;
  	cin>>n;
  	for(int i=1;i<=n;i++)
  	{
  		cin>>a[i];
  		add(a[i],i,1);//建反向边,方便后面树形dp 
  		fat[i]=a[i];
	}
	int ans=0;
  	for(int i=1;i<=n;i++)
  	{
  		if(vs[i])continue;	
  		int id=i;
  		while(!vs[id])
  		{
  			vs[id]=1;
  			id=a[id];
		}
		rt=id;
  		int mx=0;
  		f=false;
  		gao(rt);
  		mx=max(mx,max(dp[rt][0],dp[rt][1]));
  	//	cout<<dp[rt][0]<<"  "<<dp[rt][1]<<" == =  "<<endl;
  		f=true;
  		gao(rt);
  		mx=max(mx,dp[rt][0]);
  	//	cout<<"wwqrreq                   rrwe    "<<dp[rt][0]<<endl;
  		ans+=mx;
  	//	cout<<" 00 0 0     "<<mx<<"  "<<rt<<endl;
	}
	cout<<ans<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值