[ZJOI2008]骑士,bzoj1040,基环树Dp

正题

      我发现0809的OI好喜欢Dp啊。

      这个题可以把骑士们之间的仇恨关系转化为一张无向图,为什么是无向?因为我们不能在一起。

      接着可以发现相邻两个不能同时选,求最大价值,那么我们对于每一个联通块做一次基环树Dp就可以了。

      类似没有上司的舞会?

      具体就是找出一条在环上的边,砍掉,然后强制左边的点不选或者右边的点不选,取最大值就可以了。

      但是希望注意的是无向图找环的方法,楼主提供了一种,希望写炸的同学多检查找环。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
 
int n;
int d[1000010];
struct edge{
    int y,next;
}s[2000010];
int first[1000010];
bool pre[1000010],vis[1000010];
long long f[1000010][2];
int len=1,fir,sec,key;
long long ans=0,temp;
 
void ins(int x,int y){
    s[++len]=(edge){y,first[x]};first[x]=len;
    s[++len]=(edge){x,first[y]};first[y]=len;
}
 
bool dfs(int x,int las){
    pre[x]=true;
    for(int i=first[x];i!=0;i=s[i].next){
        int y=s[i].y;
        if((las^1)==i) continue;
        if(pre[y]) {fir=x,sec=y,key=i;return true;}
        if(dfs(y,i)) return true;
    }
    pre[x]=false;
    return false;
}
 
void get_ans(int x,int last){
    f[x][1]=d[x];f[x][0]=0;vis[x]=true;
    for(int i=first[x];i!=0;i=s[i].next){
        int y=s[i].y;
        if(y==last || i==key || i==(key^1)) continue;
        get_ans(y,x);
        f[x][0]+=max(f[y][0],f[y][1]);
        f[x][1]+=f[y][0];
    }
}
 
int main(){
    scanf("%d",&n);
    int x;
    for(int i=1;i<=n;i++){
        scanf("%d",&d[i]);
        scanf("%d",&x);
        ins(i,x);
    }
    for(int i=1;i<=n;i++) if(!vis[i]){
        if(!dfs(i,0)) continue;
        get_ans(fir,0);
        temp=f[fir][0];
        get_ans(sec,0);
        ans+=max(temp,f[sec][0]);
    }
    printf("%lld\n",ans);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值