• 骑士,题解


    题目直接链接

    题意:

      中文题,也挺明白的,就不过多的叙述。

    分析:

      首先我们把条件转换一下,其实a憎恨b和b憎恨a的效果是等价的,说白了就是a和b不选在一起,然后就是考虑一下,我们先建一个图,然后找一下连通分量(当然是无向图了,刚才已经说了,是等价的)每个联通分量的结果是不会互相影响的,因为没有相互憎恨的关系,那这样是不是想到了一道题:没有上司的舞会。类似的,但是这个是图,那个是树。

      而在图上dp就不是很好了,但是我们可以考虑一下这个图的特殊性质:如果某个分量(边去了重)里有x个点,那么他只可能有x-1个边或者x个边,因为少于x-1个边将不会联通,而每个点又最多为次分量提供一条边(如果重了就是不再提供),当然如果是x-1多条边那么就非常简单了,那就直接树形dp就好了。

      我们来考虑一下如有x个边怎么样,如果有x个边的我们可以把他转换成x-1条边的树,怎么转换呢,我们可以这样想,x边的联通图去掉1条特定的边,那么他一定能成为一棵树,我们只要找到可以的一条边然后两次Dfs进行dp,第一次不取这条边连接的某个点,第二次不取另一个点然后取max就好了,这条边怎么找到呢,其实找到环上的任何一条边都可以。而找环就可应直接读边的时候处理出来就好了,最后就是代码。

    #include <cstdio>
    #include <string>
    using namespace std;
    const int maxn=1000000+10;
    long long w[maxn];
    int e[maxn];
    int f[maxn];
    int x1[maxn];
    int x2[maxn];
    int t[maxn];
    long long Dp[maxn][2];
    bool vis[maxn];
    //并查集
    void Init(int n){
        for(int i=1;i<=n;i++)
            f[i]=i;
    }
    int Find(int a){
        return a==f[a]?a:(f[a]=Find(f[a]));
    }
    void Co(int a,int b){
        int fa=Find(a);
        int fb=Find(b);
        f[fb]=fa;
    }
    //边表
    int head[maxn];
    struct E{
        int to;
        int next;
        E(){
            to=next=0;
        }
    }ed[maxn*2];
    int tot;
    void J(int a,int b){
        tot++;
        ed[tot].to=b;
        ed[tot].next=head[a];
        head[a]=tot;
    }
    void Dfs(int x,int fa,int ix,int id){
        vis[x]=1;//只是供后面用
        Dp[x][0]=0;
        if(x==ix)//不能选x
            Dp[x][1]=0;
        else
            Dp[x][1]=w[x];
        for(int i=head[x];i;i=ed[i].next){
            if(ed[i].to==fa||i==id||i==((id%2)?(id+1):(id-1)))
                continue;
            Dfs(ed[i].to,x,ix,id);
            Dp[x][0]+=max(Dp[ed[i].to][1],Dp[ed[i].to][0]);
            Dp[x][1]+=Dp[ed[i].to][0];
        }
    }
    int main(){
        int n;
        int gs=0;
        scanf("%d",&n);
        Init(n);
        for(int i=1;i<=n;i++){
            scanf("%lld%d",&w[i],&t[i]);
            if(t[t[i]]!=i){//重边不再加
                J(i,t[i]);
                J(t[i],i);
            }
            else
                continue;
            if(Find(i)!=Find(t[i]))
                Co(i,t[i]);
            else{
                gs++;//处理出需要的边
                x1[gs]=i;
                x2[gs]=t[i];
                e[gs]=tot;
            }
        }
        long long ans=0;
        for(int i=1;i<=gs;i++){//x边的分量的处理
            Dfs(x1[i],0,x2[i],e[i]);
            long long js1=max(Dp[x1[i]][1],Dp[x1[i]][0]);
            Dfs(x2[i],0,x1[i],e[i]);
            long long js2=max(Dp[x2[i]][1],Dp[x2[i]][0]);
            ans+=max(js1,js2);
        }
        for(int i=1;i<=n;i++)//(x-1)边的分量的处理
            if(!vis[i]){
                Dfs(i,0,0,0);
                ans+=max(Dp[i][0],Dp[i][1]);
            }
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    C/C++的区别
    stm32之UCOS-III
    PID控制及整定算法
    PCB设计基础及技巧
    电路的一些基本理论
    stm32与三菱PLC通信
    stm32之外设控制
    stm32之内部功能
    JavaScript数组方法详解
    git新建关联克隆仓库指令
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/12760082.html
Copyright © 2020-2023  润新知