基环树:
是一种有 n 个点 n 条边,且图中只存在一个环的图被称为基环树(环套树)
分三类:
-
无向树
-
外向树(每个点只有一条入边)
-
内向树(每个点只有一条出边)
基本思路:
1、深搜找环
2、断坏成树,对树根进行dp
实例: 骑士
思路:
1、对于每颗基环树断开环上任意一条边,对这条边的两个端点分别做一次树形dp,两次答案去max
2、累加每颗基环树的max
Code:
#include<bits/stdc++.h>
#define bug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
const int N = 1e6 + 100;
const int mod = 1e9 + 7;
typedef long long ll;
int n,cnt,r1,r2;
int val[N],head[N];
bool vis[N];
struct Node {
int to,nxt;
} e[N];
ll dp[N][2],res;
void add(int u,int v) {
++cnt;
e[cnt] = {v,head[u]};
head[u] = cnt;
}
void Find(int u,int rt) {
vis[u] = 1;
for(int i=head[u]; i; i=e[i].nxt) {
int v = e[i].to;
if(v==rt) {
r1=v;
r2=u;
return;
}
if(!vis[v]) Find(v,rt);
}
}
ll dfs(int u,int rt) {
dp[u][0] = 0;
dp[u][1] = val[u];
for(int i=head[u]; i; i=e[i].nxt) {
int v = e[i].to;
if(v==rt) continue;
dfs(v,rt);
dp[u][0] += max(dp[v][0],dp[v][1]);
dp[u][1] += dp[v][0];
}
return dp[u][0];
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
int w,u;
scanf("%d%d",&val[i],&u);
add(u,i);
}
for(int i=1; i<=n; i++) {
if(!vis[i]) {
r1=r2=0;
Find(i,i);
if(r1) {
ll t1 = dfs(r1,r1);
ll t2 = dfs(r2,r2);
//cout<<t1<<" "<<t2<<endl;
res += max(t1,t2);
}
}
}
printf("%lld",res);
return 0;
}
/*
3
10 2
20 3
30 1
*/
写的不好 仅供参考
资源来源: 董晓算法