首页 > 代码库 > BZOJ 1040 骑士(环套树DP)

BZOJ 1040 骑士(环套树DP)

如果m=n-1,显然这就是一个经典的树形dp。

现在是m=n,这是一个环套树森林,破掉这个环后,就成了一个树,那么这条破开的边连接的两个顶点不能同时选择。我们可以对这两个点进行两次树形DP根不选的情况。

那么答案就是每个森林的max()之和。

 

技术分享
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF (LL)1<<60
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==-) flag=1;
    else if(ch>=0&&ch<=9) res=ch-0;
    while((ch=getchar())>=0&&ch<=9)  res=res*10+(ch-0);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(-); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+0);
}
const int N=1000005;
//Code begin...

struct Edge{int p, next, flag;}edge[N<<1];
int head[N], cnt=2, node[N], res[2], p;
bool vis[N];
LL dp[2][N][2];

void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;}

void dfs(int x, int fa)
{
    vis[x]=true;
    for (int i=head[x]; i; i=edge[i].next) {
        int v=edge[i].p;
        if (v==fa) continue;
        if (vis[v]==true) {
            if (p==0) res[0]=x, res[1]=v, p=1, edge[i].flag=edge[i^1].flag=1;
            continue;
        }
        dfs(v,x);
    }
}
void dfs_dp(int x, int fa, int flag)
{
    for (int i=head[x]; i; i=edge[i].next) {
        int v=edge[i].p;
        if (v==fa||edge[i].flag) continue;
        dfs_dp(v,x,flag);
        dp[flag][x][0]+=max(dp[flag][v][0],dp[flag][v][1]);
        dp[flag][x][1]+=dp[flag][v][0];
    }
    dp[flag][x][1]+=node[x];
}
int main ()
{
    int n, u, w;
    LL ans=0;
    scanf("%d",&n);
    FOR(i,1,n) scanf("%d%d",&w,&u), add_edge(u,i), add_edge(i,u), node[i]=w;
    FOR(i,1,n) {
        if (vis[i]) continue;
        p=0; dfs(i,0);
        dfs_dp(res[0],0,0); dfs_dp(res[1],0,1);
        ans+=max(dp[0][res[0]][0],dp[1][res[1]][0]);
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

BZOJ 1040 骑士(环套树DP)