/*题意: 一图N个点,N条边,取某个点会有信任点,同时某个点与其它的后继结点同时取的话,
它的信任点会改变一个值,问怎么取点,使得总信任点最大
分析:因为只有N个点,N条边,所以肯定是几个环(M个点M条边)加上一些尾巴,
对于环外的点,不断向上缩,有dp[i][0]+=Max(dp[soni][0],dp[soni][1]);
dp[i][1]+=Max(dp[soni][0],dp[soni][1]+g[soni]); 而对于每个环,枚举其中一个点的状态,
就变成一条链了,也可以运用上面的转移方程了 */
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=210000;
long long in[maxn],f[maxn],g[maxn],next[maxn],q[maxn];
long long dp[maxn][2],dp1[maxn][2];
bool flag[maxn];
long long Max(long long a,long long b)
{
return a>b? a:b;
}
long long DFS1(long long f,long long now,long long dp[][2],long long flag)
{
long long i,j,k;
k=now;
i=next[k];
while(i!=f)//由k更新i,所以i到f那就不必了
{
dp[i][0]+=Max(dp[k][0],dp[k][1]);
dp[i][1]+=Max(dp[k][0],dp[k][1]+g[k]);
k=next[k];
i=next[k];
}
//退出时i(f)为k的下一个结点
if(flag) dp[k][1]+=g[k];//如果f和k同时取的话
return Max(dp[k][0],dp[k][1]);
}
long long DFS(long long now)//含now的环
{
long long i,j,jj,k;
k=now;
i=next[k];
dp1[i][0]+=dp[k][0];//now不取
dp1[i][1]+=dp[k][0];
j=DFS1(now,i,dp1,0);
dp[i][0]+=dp[k][1];//now取
dp[i][1]+=dp[k][1]+g[k];
jj=DFS1(now,i,dp,1);
return Max(j,jj);//两个选择中较优的
}
int main()
{
long long n,i,j,k,top,ii,jj;
long long sum;
while(scanf("%lld",&n)!=EOF)
{
memset(in,0,sizeof(in));
for(i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&f[i],&g[i],&next[i]);
in[next[i]]++;//入度
}
memset(dp,0,sizeof(dp));
memset(flag,false,sizeof(flag));
for(top=0,i=1;i<=n;i++)
{
dp[i][1]=f[i];//取的话肯定有f[i]
if(!in[i])//入度为0,就说明是尾巴,要往上缩
q[top++]=i;
}
while(top)//将所有环外的点都算出来
{
k=q[--top];
flag[k]=true;
i=next[k];
dp[i][0]+=Max(dp[k][0],dp[k][1]);
dp[i][1]+=Max(dp[k][0],dp[k][1]+g[k]);
if(--in[i]==0LL)
q[top++]=i;
}
memcpy(dp1,dp,sizeof(dp));//因为要枚举一个环上的点的状态,所以这备份一个
for(sum=0,i=1;i<=n;i++)
{
if(!flag[i])//说明还有入度,即是环上的点
{
sum+=DFS(i);//加上这个环的最优解
flag[i]=true;//标记这个环上的点
for(j=next[i];j!=i;j=next[j])
flag[j]=true;
}
}
printf("%lld\n",sum);
}
return 0;
}
本文探讨了一种算法,用于解决在给定图结构的情况下,如何通过选择特定节点以达到最大化总信任点的目标。该算法考虑了节点间的依赖关系和信任点的变化规则,通过递归地处理环形结构和尾部节点,最终确定最优节点选择方案。
754





