P2607 [ZJOI2008]骑士

【题意】

N 个骑士,每个骑士有且仅有一个厌恶的骑士(不会是他自己),每个骑士都有一个战斗力,现要求从中选取一些骑士,使得这 N 个骑士之间相互不厌恶的同时,其战斗力之和最大,输出这个最大的战斗力之和

【分析】

这题是基环树森林求最大权独立集

P1453 城市环路  的升级版直接对于每个基环树计算即可,答案累加

唯一就是找环稍微麻烦了一点

 

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+5;
const long long inf=1e17;
int n,root,cnt,v[maxn],fa[maxn],vis[maxn],head[maxn];
long long f[maxn][2];
struct edge
{
    int to,nxt;
}e[maxn];
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].nxt=head[x];
    head[x]=cnt;
}
long long ans;
void dfs(int x)
{
    vis[x]=1; 
    f[x][1]=v[x]; f[x][0]=0;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==root)
        {
            f[to][1]=-inf;
            continue;
        }
        dfs(to);
        f[x][0]+=max(f[to][0],f[to][1]);
        f[x][1]+=f[to][0];
    }
}
void circle(int x)
{
    vis[x]=1;
    root=x;
    while(!vis[fa[root]])
    {
        root=fa[root];
        vis[root]=1;
    }
    dfs(root);
    long long ans1=max(f[root][0],f[root][1]);
    vis[root]=1;
    root=fa[root];
    dfs(root);
    long long ans2=max(f[root][0],f[root][1]);
    ans+=max(ans1,ans2);
}
int main()
{
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    scanf("%d",&n);
    int x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&v[i],&x);
        add(x,i); fa[i]=x;
    }
    for(int i=1;i<=n;i++)
        if(!vis[i])
            circle(i);
    printf("%lld",ans);
    return 0;
}

 

posted @ 2021-07-04 12:33  andyc_03  阅读(51)  评论(0编辑  收藏  举报