GT and set
有N個集合,每個集合中有Ai個數。 你要將這N個集合劃成L個部分,使得每個部分的集合至少有一個共有的數。 如果至少有一個解輸出YES,否則輸出NO
第一行一個數T表示數據組數。(T≤20) 對於每一組數據: 第一行兩個數N和L。 接下來N行每行描述一個集合: 第一個數Ai表示該集合的大小,之後x個互不相同的整數表示該集合的元素。 集合裏的數字都是正整數且不大於300. 1≤N≤30,1≤L≤5,1≤Ai≤10,1≤L≤N hack時建議輸出最後一行的行末回車;每一行的結尾不要輸出空格。
對於每組數據輸出一行YES或NO
2 2 1 1 1 1 2 3 2 3 1 2 3 3 4 5 6 3 2 5 6
NO YES
對於第二個樣例,有三個集合{1 2 3},{4 5 6},{2 5 6} 你要劃成兩個部分。 有一種方案是把第二個和第三個集合劃成一個部分,第一個在另一個部分。有一種方案是把第二個和第三個集合劃成一個部分,第一個在另一個部分。 第二個和第三個集合的數字有一個交集{6},所以合法。 還有一種劃分方案就是把第一個和第三個集合劃成一個部分,第二個在另一個部分。
題解:
可能一些選手題意不是很清楚,我這裏再提供一個轉化後的問題:給出N個集合。每次你可以指定一個數,然後所有包含這個元素的集合可以被刪掉。問你能否經過最多L輪操作使得所有集合都被刪掉。因爲LL只有5,考慮直接dfs。對於第一個集合,我們枚舉它的那個公共的數是多少。然後線性掃描過去,找到接下來第一個沒有這個數的集合。(它顯然不能通過這個公共的數與第一個數在同一個部分)。對於這個集合,再枚舉它公共的數是多少,然後線性掃描過去找到第一個沒有這兩個數的集合……這樣重複5次後如果還是沒有,就直接NO好了。若中途掃完序列就是YES。
自己也寫了一個dfs暴力,但不知道爲什麼一直TLE。。。ORZ。。。
學習了別人的代碼之後,發現就是:哇塞,竟然還可以這樣搞。。。
其實自己之前做poj有一道題目與此類似,但是自己還是沒能想到ORZ。。。。就是如果只判斷一個數是否在一個集合裏面,只有兩個狀態,這個數還不大的話,那麼bitset一定要加入考慮的範圍。
具體解釋見代碼:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#include <bitset>
using namespace std;
int n, divide;//表示當前集合數和所要的劃分數
bitset<305>set[35];//表示該集合裏面有哪些數,一共最多30個集合
int dfs(int id, bitset<305>*tmp)
{
if (id == n)//如果能夠抵達n,說明n個集合都已經劃分好了,自然正確了
{
return 1;
}
bitset<305>ans[35];
for (int i = 0; i < divide; i++)//tmp代表各個劃分當前的狀態,即這個劃分中是靠哪一個數來維繫的
{
ans[i] = tmp[i];
}
for (int i = 0; i < divide; i++)//枚舉該集合能弄到哪一個劃分中,沒有可去的就單獨到一個劃分裏面去
{
ans[i] = tmp[i]&set[id];
if (ans[i].count())//說明這個集合和之前的集合有交集,即可以放入到這個劃分中,掃下一個集合
{
if (dfs(id + 1, ans))
return 1;
}
ans[i] = tmp[i];//該集合不放入到這個劃分中
}
return 0;
}
int main()
{
//freopen("i.txt","r",stdin);
//freopen("o.txt","w",stdout);
int t, cnt, x;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, ÷);
bitset<305>tmp[35];
for (int i = 0; i < n; i++)
{
scanf("%d", &cnt);
set[i].reset();
for (int j = 0; j < cnt; j++)
{
scanf("%d", &x);
set[i][x] = 1;
}
for (int j = 0; j <= 300; j++)
{
tmp[i][j] = 1;
}
}
int flag = dfs(0, tmp);
if (flag)
puts("YES");
else
puts("NO");
}
//system("pause");
return 0;
}