• Luogu P1525 关押罪犯


       这又是一道坑题!

      思想进行了大幅转变,并查集炸了之后终于搞出了一种奇葩的算法,终于卡时间A了。

      把思路按顺序理一理。

      先把边从大到小排序一下。

      <1> 看完题目,我去这不是并查集模板么吗,马上敲了个裸并查集,判断两个点如果之前已经联通了,直接退出输出当前值即可。

      CODE(WA)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=20005,M=100005;
    struct data
    {
        int l,r,s;
    }e[N];
    int father[N],i,n,m;
    inline void read(int &x)
    {
        x=0; char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    }
    inline int comp(data a,data b) { return a.s>b.s; }
    inline int getfather(int k) { return k==father[k]?k:father[k]=getfather(father[k]); }
    int main()
    {
        read(n); read(m);
        for (i=1;i<=n;++i)
        father[i]=i;
        for (i=1;i<=m;++i) 
        read(e[i].l),read(e[i].r),read(e[i].s);
        sort(e+1,e+m+1,comp);
        for (i=1;i<=m;++i)
        {
            int fx=getfather(e[i].l),fy=getfather(e[i].r);
            if (fx==fy) break;
            father[fx]=fy;
        }
        printf("%d",e[i].s);
        return 0;
    }

      帅气得搞了50分·。

      <2> 上一种打法为什么会WA,是因为没有考虑到一种情况:如果两个人之间的距离是偶数,那么他们应该在同一个监狱(类似于我的敌人的敌人就是我的朋友)。类似的思想在食物链这道题里面也有。

      然后就是一道带权并查集的模板题了(可是我不会) 

      不过可以用补集的做法来搞

      开两倍的数组,每次连边的时候把x和y+n相连,y和x+n相连。这样如果两个点的父节点相同那么它们之间的距离肯定是偶数。

      CODE(TLE)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=20005,M=100005;
    struct data
    {
        int l,r,s;
    }e[N];
    int father[N*2],i,n,m;
    inline void read(int &x)
    {
        x=0; char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    }
    inline int comp(data a,data b) { return a.s>b.s; }
    inline int getfather(int k) { return k==father[k]?k:father[k]=getfather(father[k]); }
    int main()
    {
        read(n); read(m);
        for (i=1;i<=n*2;++i)
        father[i]=i;
        for (i=1;i<=m;++i) 
        read(e[i].l),read(e[i].r),read(e[i].s);
        sort(e+1,e+m+1,comp);
        for (i=1;i<=m;++i)
        {
            int fx=getfather(e[i].l),fy=getfather(e[i].r);
            if (fx==fy) { printf("%d",e[i].s); return 0; } 
            father[fx]=getfather(e[i].r+n);
            father[fy]=getfather(e[i].l+n);
        }
        puts("0");
        return 0;
    }

      然后蜜汁TLE了4个点

      <3> 终于,发现了一种神奇的算法。因为已经对边长排过序,并且稍微想一想就可以得出如果到这一条边不能满足要求,那么所有比它小的边绝对也满足不了。

      于是——二分。

      对于二分出来的边长,只保留比它长的边,再跑一遍染色即可。

      所谓染色,就是把一个点染上一种颜色(例如1),再把与它相邻的点染上另一种颜色即可(例如2)。

      如果发现一个点与之相连的点颜色和它一样,说明不可行,return 掉即可。

      BFS实现玄学复杂度,常数小的应该能卡过去

      CODE(AC)

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N=20005,M=100005;
    vector <int> a[N],l[N];
    int n,m,i,j,ans,col[N],q[N*2+10],e[M],x,y;
    inline void read(int &x)
    {
        x=0; char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    }
    inline int comp(int a,int b) { return a>b; }
    inline bool check(int x)
    {
        memset(col,0,sizeof(col));
        for (i=1;i<=n;++i)
        if (!col[i]) 
        {
            memset(q,0,sizeof(q));
            int head=0,tail=1;
            q[1]=i; col[i]=1;
            while (head<tail)
            {
                int now=q[++head];
                for (j=0;j<a[now].size();++j)
                {
                    int k=a[now][j];
                    if (l[now][j]>x)
                    {
                        if (!col[k]) { col[k]=3-col[now]; q[++tail]=k; } else
                        if (col[k]==col[now]) return 0;
                    }
                }
            }
        }
        return 1;
    }
    int main()
    {
        read(n); read(m);
        for (i=1;i<=m;++i)
        {
            read(x); read(y); read(e[i]);
            a[x].push_back(y); l[x].push_back(e[i]); 
            a[y].push_back(x); l[y].push_back(e[i]);
        }
        sort(e+1,e+m+1,comp);
        int l=1,r=m+1;
        while (l<=r)
        {
            int mid=l+r>>1;
            if (check(e[mid])) ans=mid,l=mid+1; else r=mid-1;
        }
        printf("%d",e[ans]);
        return 0;
    }
  • 相关阅读:
    C# WinForm 关于窗体最大化时的是否全屏效果与是否遮盖任务栏
    C# winform 无边框 窗体的拖动
    lenovo 联想笔记本ideapad 320c-15改装win7问题
    解决WIN7第一次开机冷启动QQ未响应的办法
    WIN10X64_LTSB2016极限精简版by双心
    RAMOS和SSD对比
    联想IDEAPAD 320C-15笔记本显卡驱动问题
    WIN7以上系统安装VB6的解决办法,附上个批处理。
    吐槽下银联1分钱乘公交
    QQ聊天框变成方框口口口口的解决办法
  • 原文地址:https://www.cnblogs.com/cjjsb/p/8097409.html
Copyright © 2020-2023  润新知