HDU 5506 - BestCoder Round #60 - GT and set
题目链接 : http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=641&pid=1003
题意 :
给N集合, 每个集合由若干个正整数组成,
要求划分为L个部分, 使得每个部分的所有集合的交集非空
能划分输出YES, 否则NO
思路 :
一共N个集合, 划分的个数为1 - N个, 所以当 L > N 时必然是不行的
考虑如何取到最小的划分个数cnt, 如果 cnt <= L 则可行
方法 :
记录所有的数出现过的次数
每次都找一个出现次数最多的数, 将存在该数的集合作为一个划分, cnt++, 将该划分中所有集合中的数出现次数都减一, 直到不存在剩余数字为止, 再将cnt与L进行比较
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 35; const int MAX_NUM = 3e2+10; int sett[MAXN][MAX_NUM]; int number_cnt[MAX_NUM]; int num[MAXN]; bool vis[MAXN]; int Max_Cnt() { int res = 0; for(int i = 0; i < MAX_NUM; i++) { if(number_cnt[i] > number_cnt[res]) res = i; } return res; } void Init() { memset(number_cnt, 0, sizeof(number_cnt)); memset(vis, 0, sizeof(vis)); } int main() { int t; int n, l; scanf("%d", &t); while(t--) { Init(); scanf("%d %d", &n, &l); for(int i = 0; i < n; i++) { scanf("%d", &num[i]); for(int j = 0; j < num[i]; j++) { scanf("%d", &sett[i][j]); number_cnt[sett[i][j]]++; } } int cnt = 0; for(int i = 0; i < n; i++) { int number = Max_Cnt(); if(number == 0) break; for(int j = 0; j < n; j++) { if(vis[j] == 1) continue; for(int k = 0; k < num[j]; k++) { if(sett[j][k] == number) { vis[j] = 1; break; } } if(vis[j] == 1) { for(int k = 0; k < num[j]; k++) { number_cnt[sett[j][k]]--; } } } cnt++; } if(cnt <= l) printf("YES\n"); else printf("NO\n"); } return 0; }