题意
有N个村庄,每个村庄有一定的信仰值,占领村庄可以得到信仰值,每个村庄有一个关联村庄,同时占领关联村庄可以得到加成(可能为负),问占领一些村庄,最多可以得到多少信仰值
题解
这个DP已经不能算是树形DP了,因为有环。不过有趣的是环只有一个(可能有多个环,但是不可能存在环套环)。这样的话我们便可以破环进行DP。
如果画一下图的话可以发现这个图很像一只章鱼,我们进行DP的话,可以首先从触手的位置开始,我们可以首先从触手尖端开始DP(触手尖端为入度为0的点),一直DP到环(环上的点即便减去触手入度也不为0)。对于环上的点,我们要分情况进行DP(因为DP只能用于有向无环图),我们可以将环剪开。对于剪开的位置,我们可以选择选,可以选择不选,于是我们可以开两个DP数组分别讨论。
最后再将两个数组合并,同时将最大信仰值增加到ANS上。需要注意的是,可能有多条章鱼,所以需要进行多次DP,求总和。
注意事项
ZOJ莫名其妙的内存分配机制。。Queue在主函数循环内声明直接TLE。。声明为全局变量2700ms,声明到函数里直接600MS。。终于明白BFS为什么要开一个函数去写了。。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#include<stack>
#include<string>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define MEM(a,b) memset(a,b,sizeof(a))
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 120050
#define MOD 1000000007
#define EPS 1e-3
#define int LL
using namespace std;
int f[MAXN],g[MAXN],xnext[MAXN],in[MAXN],dp[MAXN][2],dp1[MAXN][2],p[MAXN];
int num;
bool vis[MAXN];
queue<int> q;
void dfs(int u){
p[++num]=u;
vis[u]=true;
int t=xnext[u];
if(vis[t]) return ;
dfs(t);
}
main() {
int n;
W(~scanf("%lld",&n)) {
W(!q.empty()) q.pop();
MEM(in,0);
MEM(dp,0);
MEM(dp1,0);
MEM(vis,false);
UP(i,1,n+1) {
scanf("%lld%lld%lld",&f[i],&g[i],&xnext[i]);
in[xnext[i]]++;
}
UP(i,1,n+1){
dp[i][1]=f[i];
if(in[i]==0){
q.push(i);
in[i]--;
}
}
W(!q.empty()){
int r=q.front();
q.pop();
vis[r]=true;
int k=xnext[r];
dp[k][0]+=max(dp[r][0],dp[r][1]);
dp[k][1]+=max(dp[r][0],dp[r][1]+g[r]);
if(--in[k]==0) q.push(k);
}
int ans=0;
UP(j,1,n+1){
if(!vis[j]){
num=0;
dfs(j);
memcpy(dp1,dp,sizeof(dp));
dp1[p[2]][0]+=dp1[p[1]][0];
dp1[p[2]][1]+=dp1[p[1]][0];
UP(i,3,num+1){
dp1[p[i]][0]+=max(dp1[p[i-1]][0],dp1[p[i-1]][1]);
dp1[p[i]][1]+=max(dp1[p[i-1]][0],dp1[p[i-1]][1]+g[p[i-1]]);
}
dp[p[2]][0]+=dp[p[1]][1];
dp[p[2]][1]+=dp[p[1]][1]+g[p[1]];
UP(i,3,num+1){
dp[p[i]][0]+=max(dp[p[i-1]][0],dp[p[i-1]][1]);
dp[p[i]][1]+=max(dp[p[i-1]][0],dp[p[i-1]][1]+g[p[i-1]]);
}
dp[p[num]][1]+=g[p[num]];
int tmp=0;
UP(i,1,num+1){
dp[p[i]][0]=max(dp[p[i]][0],dp1[p[i]][0]);
dp[p[i]][1]=max(dp[p[i]][1],dp1[p[i]][1]);
tmp=max(dp[p[i]][0],dp[p[i]][1]);
}
ans+=tmp;
}
}
printf("%lld\n",ans);
}
}