ZOJ 3527 树形DP(章鱼图DP)

来源:互联网 发布:手机淘宝6.5.1版本 编辑:程序博客网 时间:2024/04/29 09:00

题意

有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 LLusing 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);    }}
原创粉丝点击