正题
我发现0809的OI好喜欢Dp啊。
这个题可以把骑士们之间的仇恨关系转化为一张无向图,为什么是无向?因为我们不能在一起。
接着可以发现相邻两个不能同时选,求最大价值,那么我们对于每一个联通块做一次基环树Dp就可以了。
类似没有上司的舞会?
具体就是找出一条在环上的边,砍掉,然后强制左边的点不选或者右边的点不选,取最大值就可以了。
但是希望注意的是无向图找环的方法,楼主提供了一种,希望写炸的同学多检查找环。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n;
int d[1000010];
struct edge{
int y,next;
}s[2000010];
int first[1000010];
bool pre[1000010],vis[1000010];
long long f[1000010][2];
int len=1,fir,sec,key;
long long ans=0,temp;
void ins(int x,int y){
s[++len]=(edge){y,first[x]};first[x]=len;
s[++len]=(edge){x,first[y]};first[y]=len;
}
bool dfs(int x,int las){
pre[x]=true;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if((las^1)==i) continue;
if(pre[y]) {fir=x,sec=y,key=i;return true;}
if(dfs(y,i)) return true;
}
pre[x]=false;
return false;
}
void get_ans(int x,int last){
f[x][1]=d[x];f[x][0]=0;vis[x]=true;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(y==last || i==key || i==(key^1)) continue;
get_ans(y,x);
f[x][0]+=max(f[y][0],f[y][1]);
f[x][1]+=f[y][0];
}
}
int main(){
scanf("%d",&n);
int x;
for(int i=1;i<=n;i++){
scanf("%d",&d[i]);
scanf("%d",&x);
ins(i,x);
}
for(int i=1;i<=n;i++) if(!vis[i]){
if(!dfs(i,0)) continue;
get_ans(fir,0);
temp=f[fir][0];
get_ans(sec,0);
ans+=max(temp,f[sec][0]);
}
printf("%lld\n",ans);
}