9个半小时90pts求助
查看原帖
9个半小时90pts求助
319668
Harukawa楼主2022/3/22 21:26

从中午12点到现在还是没搞定最后一个点,头已经晕了,在此向dalao求教。

思路还是标记一个联通块里的所有点,然后断开环上的一对边,分别做dp。

其中:

存图是链式前向星存的,双向存图

断边操作只做了标记,没有实际删边

我受限于智商至今不会dp所以用的记忆化搜索代替的

自己构造的数据证明对二元环是可以正常处理的

代码如下: 90pts代码

#include <cstdio>
#include <cstring>
#define ll long long 
#define rint register int 
#define MAX(a,b) ((a)<(b)?(b):(a))
#define N 1000100

int he[N],ne[N<<1],val[N],vis[N],ed[N<<1],del[N<<1],tot=1,n;
ll ans=0,rdp[N][2];

inline void add_edge(int fm,int to){
	ne[++tot]=he[fm];
	he[fm]=tot;
	ed[tot]=to;
}

void color(int o,int fm){
	vis[o]=1;
	for(rint i=he[o];i;i=ne[i]){
		if(ed[i]==fm||del[i]) continue;
		if(!vis[ed[i]]) color(ed[i],o);
		else{
			del[i]=del[i^1]=1;	
			continue;
		}
	}
}

ll dp(int o,int c,int fm){
	if(rdp[o][c]) return rdp[o][c];
	ll tans=0,tmp;
	if(c){
		for(rint i=he[o];i;i=ne[i]){
			if(ed[i]==fm||del[i]) continue;
			tans+=dp(ed[i],0,o);
		}
		return rdp[o][c]=tans+val[o];	
	}
	for(rint i=he[o];i;i=ne[i]){
		if(ed[i]==fm||del[i]) continue;
		tmp=dp(ed[i],0,o);
		tans+=MAX(tmp,dp(ed[i],1,o));
	}
	return rdp[o][c]=tans;
}

int main(){
	scanf("%d",&n);
	for(rint i=1,to;i<=n;i++){
		scanf("%d%d",val+i,&to);
		add_edge(i,to);
		add_edge(to,i);
	}
	for(rint i=1,to;i<=n;i++){
		if(!vis[i]) color(i,0);
	}
	for(rint i=2;i<=tot;i+=2){
		if(del[i]){
			ll tmp;
			memset(rdp,0,sizeof(rdp));
			tmp=dp(ed[i],0,0);
			memset(rdp,0,sizeof(rdp));
			ans+=MAX(tmp,dp(ed[i^1],0,0)); 
		}
	}
	printf("%lld",ans);
	return 0;
}

还望大佬不吝赐教,我真的想不明白了

2022/3/22 21:26
加载中...