• HDU 2480 Steal the Treasure (并查集+贪心)


    题意:给你n个点,m条边,包括有向边与无向边,每条边都有一个权值。在每个点上都有一个人,他可以走与这个点直接相连的所有边中任意一条边一次,并且得到这个权值,就不能走了,注意这条路也只能被一个人走。问最大的权值和是多少

    首先我们可以想到每个点直接走与其相连权值最大的可以走的点,不一定是最优的,因为可能:1双向走到2权值为7,1单向走到3权值为6,这时1走到3才是最优的。但是我们可以观察得到对于单向边,我们确定起点,对于双向边,我们可以寻找两个点中最优的一个点,按照这样贪心就可以。

    首先我们按照权值排序,还有就是我们要记录这个点是否被用过,但是根据之前的想法,我们可以知道有些时候不能马上确定点,但是可以确定两点找一个。因此我们可以标记0代表没用过,1代表两个点中取一个点(其实是x个点中取x-1个点),2代表已经使用。因此我们可以想到对于单向边,确定点值为2。出现双向边,如果是(0 0)(0 1)我们只能确定为(1 1),但是出现(1 1)(0 2)(1 2)确定点值为(2 2)。(这儿有个小bug)

    现在我们要注意几个问题,首先就是如果点1点2是双向边,点2点3是双向边,则我们就要在 点1点2点3 中选两个点,所以需要并查集维护连通块,接着如果出现点1点2,点3点4,再出现点2点3,则我们就要维护两个连通块合并。最后我们可以每次都加上这个权值,再判断如果不能加这条边时就减去这个权值,这样并查集就不需要存权值了

    通过这个题我学到了,如果我们得到的多个值暂时不能确定那个值是最优的,那么我们可以先假设每个点都是最优的再存下来,接着根据后面的条件解决这个问题

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define eps 1E-8
    /*注意可能会有输出-0.000*/
    #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
    #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
    #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
    #define mul(a,b) (a<<b)
    #define dir(a,b) (a>>b)
    typedef long long ll;
    typedef unsigned long long ull;
    const int Inf=1<<28;
    const double Pi=acos(-1.0);
    const int Mod=1e9+7;
    const int Max=1010;
    const int Max2=1000100;
    struct node
    {
        int u,v,d,c;
    } edg[Max2];
    int fat[Max],vis[Max];//缩点存不确定的点 标记0 1 2
    void Init(int n)
    {
        for(int i=0; i<n+1; ++i)
        {
            fat[i]=i;
            vis[i]=0;
        }
        return;
    }
    int Find(int x)
    {
        if(x==fat[x])
            return fat[x];
        return fat[x]=Find(fat[x]);
    }
    bool cmp(struct node p1,struct node p2)//价值排序,贪心
    {
        return p1.c>p2.c;
    }
    int Union(int x,int y,int v)//此两点不确定,进行并查集的合并
    {
        int x1=Find(x);
        int y1=Find(y);
        if(x1==y1)
            return 0;
        fat[x1]=y1;
        vis[x]=vis[y]=1;
        return 1;
    }
    void Jud(int n,int x)
    {
        if(vis[x]==0)//注意
        {
            vis[x]=2;
            return;
        }
        int x1=Find(x);
        for(int i=1; i<=n; ++i)
        {
            if(Find(i)==x1)
                vis[i]=2;
        }
        return;
    }
    int Solve(int n,int m)
    {
        int ans=0;
        sort(edg,edg+m,cmp);
        for(int i=0; i<m; ++i)
        {
            ans+=edg[i].c;//每次都加上
            if(edg[i].d==0)//双向
            {
                if(!vis[edg[i].u]&&!vis[edg[i].v]||!vis[edg[i].u]&&vis[edg[i].v]==1||vis[edg[i].u]==1&&!vis[edg[i].v])//放入连通块
                    Union(edg[i].u,edg[i].v,edg[i].c);
                else if(vis[edg[i].u]!=2||vis[edg[i].v]!=2)//此处所有连通块都确定了
                {
                    if(vis[edg[i].u]==1&&vis[edg[i].v]==1)//可能不同连通块
                    {
                        if(!Union(edg[i].u,edg[i].v,edg[i].c))
                            Jud(n,edg[i].u);
                    }
                    else if(vis[edg[i].u]!=2)
                        Jud(n,edg[i].u);
                    else
                        Jud(n,edg[i].v);
                }
                else
                    ans-=edg[i].c;
            }
            else
            {
                if(vis[edg[i].u]!=2)
                    Jud(n,edg[i].u);
                else
                    ans-=edg[i].c;
            }
        }
        return ans;
    }
    int main()
    {
        int n,m;
        while(~scanf("%d %d",&n,&m))
        {
            Init(n);
            for(int i=0; i<m; ++i)
                scanf("%d %d %d %d",&edg[i].u,&edg[i].v,&edg[i].d,&edg[i].c);
            printf("%d
    ",Solve(n,m));
        }
        return 0;
    }
  • 相关阅读:
    京东优惠叠加的获取
    树莓派安装omv
    树莓派 omv 安装 nextcloud
    Nginx 502 bad gateway问题的解决方法
    mvc 前台传入后台
    关于cefsharp 获取js动态加载后的信息
    c# 使用 java的 rsa 进行签名
    树莓派基本设置
    树莓派安装raspbian
    winform界面设计
  • 原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/5898127.html
Copyright © 2020-2023  润新知