从中午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;
}
还望大佬不吝赐教,我真的想不明白了