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:; } }