• 完美标号


    测评传送门

    问题描述

    给定M个二元组(A[i], B[i]),求X[1], ..., X[N]满足:对于任意(A[i], B[i]),有|X[A[i]] - X[B[i]]| = 1成立。

    输入

    第1行,2个整数N、M。

    第2行到第M + 1行,2个整数A_i和B_i。

    输出

    第1行,1个字符串,"YES"表示有解,"NO"表示无解。

    第2行,N个整数,X_1, X_2, ..., X_N,无解则不输出。

    要求|X_i| <= 1,000,000,000,任意一解均可。

    样例

    Perfect1.in

    3 3

    1 2

    2 3

    3 1

     

    Perfect1.out

    NO

     

    Perfect2.in

    6 5

    1 2

    2 3

    3 4

    4 1

    5 6

     

    Perfect2.out

    YES

    0 1 0 1 -99 -100

     

    数据范围

    对于40%的数据,1 <= N <= 10。

    对于100%的数据,1 <= N <= 10,000,0 <= M <= 100,000,1 <= A_i, B_i <= N。


    思路:

    首先我们可以发现对于所有i对应的x[i],将x[i]填为1和0永远是最优的,因为这两个数最接近最容易构成相差为1的关系(a或者a-1也可以)

    然后40%只需要枚举所有情况即可,然后对于m个询问逐个检查即可(其实并没有m个,有很多重复的,最多只有n^2)。时间复杂度O(2^n*n^2)

    100% 与关押罪犯类似,用并查集或者二分图染色解决

    并查集:对于输入的两个点a,b,我们一定要做路径压缩,然后把a的父亲和b的父亲连接到一起,并且再设一个数组dis[i]表示i到fa[i]的距离%2;如果a和b已经在同一并查集里面了,就要看它们到根节点的距离是否不同,如果相同则说明答案为NO.

    二分图染色:对于输入的点和m条边建图之后,从1开始dfs,然后这个点记录为1则下一个点记录为0....这样交替记录即可,如果某一个点已经被标记为1而它要被填为0就输出NO

    考试代码

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    const int MX=2e5+1;
    int n,m,cnt,x[MX],first[MX],dfn[MX],k;
    bool flag=false;
    struct Edge {
        int to,next;
    }edge[MX]; 
    
    void add(int from,int to)
    {
        edge[++cnt].to=to;
        edge[cnt].next=first[from];
        first[from]=cnt;
    }
    
    void dfs(int from,int last)
    {
        if(!dfn[from]){
            dfn[from]=++k;
            x[from]=~x[last];
        }
            
        else {
            if(abs(x[from]-x[last])!=1) 
            flag=true;
            return ;
        }
            
        for(int i=first[from];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if(to==last) continue;
            dfs(to,from);
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i)
        {
            int from,to;
            scanf("%d%d",&from,&to);
            add(from,to);
            add(to,from);
        }
        for(int i=1;i<=n;++i) 
        {
            flag=false;
            if(!dfn[i]) {
                dfs(i,0);
                if(flag) {
                    printf("NO");
                    return 0;
                }
            }
        }
        puts("YES");
        for(int i=1;i<=n;++i) 
            printf("%d ",x[i]);
        return 0;
    }

    修改代码

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    const int MX=2e5+1;
    int n,m,cnt,x[MX],first[MX];
    bool vis[MX];
    bool flag=false;
    struct Edge {
        int to,next;
    }edge[MX]; 
    
    void add(int from,int to)
    {
        edge[++cnt].to=to;
        edge[cnt].next=first[from];
        first[from]=cnt;
    }
    
    void dfs(int from,int last)
    {
        x[from]=1^x[last];
        for(int i=first[from];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if(to==last) continue;
            if(!vis[to]) vis[to]=1;
            else {
                if(abs(x[from]-x[to])!=1) {
                    printf("NO");
                    exit(0);
                }
                else continue;
            }    
            dfs(to,from);
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i)
        {
            int from,to;
            scanf("%d%d",&from,&to);
            add(from,to);
            add(to,from);
        }
        for(int i=1;i<=n;++i) 
        {
            if(!vis[i]) 
                dfs(i,0);
        }
        puts("YES");
        for(int i=1;i<=n;++i) 
            printf("%d ",x[i]);
        return 0;
    }
    从0到1很难,但从1到100很容易
  • 相关阅读:
    Vue.js 初尝试
    docker 搭建lnmp开发环境
    【转】【Salesfoece】在 Apex 中得到 sObject 的信息
    【转】【Salesfoece】Approval Process 在 Apex 中的使用
    【转】【Salesfoece】Apex 中 PageReference 的使用
    「codeforces
    「二次剩余」Tonelli
    「loj
    pytest---mock使用(pytest-mock)
    Django---setting文件详解
  • 原文地址:https://www.cnblogs.com/qseer/p/9524285.html
Copyright © 2020-2023  润新知