HDU 5506:GT and set bitset+暴力

GT and set

 
 Accepts: 35
 
 Submissions: 194
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
問題描述
NN個集合,每個集合中有A_iAi個數。
你要將這NN個集合劃成LL個部分,使得每個部分的集合至少有一個共有的數。
如果至少有一個解輸出YESYES,否則輸出NONO
輸入描述
第一行一個數T表示數據組數。(TT\leq2020)

對於每一組數據:
第一行兩個數NNLL。
接下來NN行每行描述一個集合:
第一個數A_iAi表示該集合的大小,之後xx個互不相同的整數表示該集合的元素。
集合裏的數字都是正整數且不大於300300.

1\leq1NN\leq30301\leq1L\leq5L51\leq1A_iAi\leq10101 \leq L \leq N1LN

hack時建議輸出最後一行的行末回車;每一行的結尾不要輸出空格。
輸出描述
對於每組數據輸出一行YESYESNONO
輸入樣例
2
2 1
1 1
1 2
3 2
3 1 2 3
3 4 5 6
3 2 5 6
輸出樣例
NO
YES
Hint
對於第二個樣例,有三個集合{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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章