HYSBZ/BZOJ 1040 [ZJOI2008] 骑士 - 基环树&树形dp

题目描述

分析:

  • 题目中的边是无向边,因为两个人在一起总有一个会不开心。
  • 因为关系不确定,所以这是个森林。
  • 因为边数=点数,所以每个连通块可能是树,也可能是只有一个环的基环树(基环树就是一棵树但多了且只多了一条返祖边(仅出现一个环)),所以考虑找到环上的亮点,断开这条边,分别限制两个点不能取,以点为根做树形dp,ans加上这样搞出来的最大值(因为两个点不能同时取)。
  • 树形dp:dp[u][0/1] (0:不取u;1:要取u)
    dp[u][0]=max{dp[u.son][0],dp[u.son][1]}

    dp[u][1]=fight[u]+dp[u.son][0]
  • 提示:可能会有互相恨的情况,但N太大无法在读入时给边判重,在dfs(dfs来找环)的时候,要判一下,不能两次走同一个儿子。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 1000000
typedef long long LL;

struct node{
    int v;
    node *next;
}edge[MAXN*2+10],*adj[MAXN+10],*ecnt=&edge[0];

int n,fight[MAXN+10],r1,r2,flag,father[MAXN+10];
bool vis[MAXN+10];
LL ans,dp[MAXN+10][2];

void addedge(int u,int v)
{
    node *p=++ecnt;
    p->v=v;
    p->next=adj[u];
    adj[u]=p;
}
void read()
{
    int x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&fight[i],&x);
        addedge(i,x);
        addedge(x,i);
    }
}
void dfs1(int u,int fa) //to find the circle(if there is one)
{
    vis[u]=true,father[u]=fa;
    for(node *p=adj[u];p;p=p->next){
        if(p->v==fa) continue;
        if(vis[p->v]&&father[p->v]!=u){
            r1=u;
            r2=p->v;
            continue;
        }
        dfs1(p->v,u);
    }
}
void dfs2(int u,int fa) // for dp on the tree
{
    dp[u][0]=dp[u][1]=0;
    father[u]=fa;
    for(node *p=adj[u];p;p=p->next){
        if(p->v==fa||p->v==flag||father[p->v]==u) continue;
        dfs2(p->v,u);
        dp[u][0]+=max(dp[p->v][0],dp[p->v][1]);
        dp[u][1]+=dp[p->v][0];
    }
    dp[u][1]+=fight[u];
}
void DP()
{
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++){
        if(vis[i]) continue;
        r1=r2=-1;
        memset(father,-1,sizeof father);
        dfs1(i,0);
        if(r1==-1){
            flag=-1;
            memset(father,-1,sizeof father);
            dfs2(i,0);
            ans+=max(dp[i][0],dp[i][1]);
        }
        else{
            //强制让r1不要和强制r2不要
            flag=r1;
            dp[r1][0]=0;
            memset(father,-1,sizeof father);
            for(node *p=adj[r1];p;p=p->next){
                if(p->v==r2) continue;
                dfs2(p->v,r1);
                dp[r1][0]+=max(dp[p->v][0],dp[p->v][1]);
            }
            LL tmp=dp[r1][0];
            flag=r2;
            dp[r2][0]=0;
            memset(father,-1,sizeof father);
            for(node *p=adj[r2];p;p=p->next){
                if(p->v==r1) continue;
                dfs2(p->v,r2);
                dp[r2][0]+=max(dp[p->v][0],dp[p->v][1]);
            }
            ans+=max(tmp,dp[r2][0]);
        }
    }
}
int main()
{
    read();
    DP();
    printf("%lld\n",ans);
}
posted @ 2016-02-05 21:54  KatarinaYuan  阅读(102)  评论(0编辑  收藏  举报