P8252 [NOI Online 2022 提高组] 讨论题解

题意

有 $n$ 个人,有 $n$ 道题,每个人有一个自己会的题的集合,求是否存在任意两个人他们的集合相交且互不包含。

分析

我才不会说这是KH神教我的

我们从无解的情况开始考虑,那么任意两个人之间要么没有交集,要么包含,所以我们可以设计这样的算法:贪心地想,按集合从大到小找,建一个树形结构(感性理解吧,想象一下),结点是题的编号。首先把最大的那一坨染成他的编号,然后再依次插入每个人,在遍历的过程中我们记录出现的颜色,记录之后顺便把他染成当前的编号,如果在遍历过程中出现了两种不同的颜色,证明我们找到了合法解,输出即可。

#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<vector>
#include<string>
using namespace std;
const int N = 1e6 + 5;
int id[N],k[N],col[N],n,t;
vector<int>v[N];
inline bool cmp(int x,int y){
    return k[x] > k[y];    
}
int main(){
    //freopen("discuss2.in","r",stdin); 
    scanf("%d",&t);
    while(t--){
        memset(k,0,sizeof(k));
        memset(col,0,sizeof(col));
        memset(id,0,sizeof(id));
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d",k+i);
            id[i] = i;
            v[i].clear();    
            for(int x,j=1;j<=k[i];++j){
                scanf("%d",&x);
                v[i].push_back(x);
            }
        }
        sort(id+1,id+1+n,cmp);//按集合大小降序 
        for(int x : v[id[1]])col[x] = id[1];//最大的一坨染色 
        int cnt = 1;
        k[0] = 1e9;
        for(int i=2;i<=n;++i){
            cnt++;
            int flag = 0,color = 0;
            for(int x : v[id[i]]){
                if(color != col[x] && flag){//第二种颜色 
                    printf("YES\n%d %d\n",id[i],k[col[x]] < k[color] ? col[x] : color);//避免颜色为0 
                    goto QWQ;    
                }
                if(flag == 0)flag = 1;//第一种颜色 
                color = col[x];//记录颜色 
                col[x] = id[i];//染色 
            }
        }
        puts("NO");
        QWQ:;
    }
}

 

posted @ 2022-04-06 23:47  Xu_brezza  阅读(53)  评论(0编辑  收藏  举报