河南省藍橋杯第十屆省賽-9- 糖果

題目描述:

【問題描述】 糖果店的老闆一共有 M 種口味的糖果出售。爲了方便描述,我們將 M 種 口味編號 1 ∼ M。 小明希望能品嚐到所有口味的糖果。遺憾的是老闆並不單獨出售糖果,而 是 K 顆一包整包出售。 幸好糖果包裝上註明了其中 K 顆糖果的口味,所以小明可以在買之前就知 道每包內的糖果口味。 給定 N 包糖果,請你計算小明最少買幾包,就可以品嚐到所有口味的糖 果。

【輸入格式】 第一行包含三個整數 N、M 和 K。 接下來 N 行每行 K 這整數 T1, T2, · · · , TK,代表一包糖果的口味。

【輸出格式】 一個整數表示答案。如果小明無法品嚐所有口味,輸出 −1。

【樣例輸入】 6 5 3 1 1 2 1 2 3 1 1 3 2 3 5 5 4 2 5 1 2

【樣例輸出】 2

【評測用例規模與約定】 對於 30% 的評測用例,1 ≤ N ≤ 20 。 對於所有評測樣例,1 ≤ N ≤ 100,1 ≤ M ≤ 20,1 ≤ K ≤ 20,1 ≤ Ti ≤ M。

分析:

糖果口味M種,每包糖K種口味,共N包糖

則所有糖果口味加在一起,共有2^M種狀態

即從0000,0001,......,1111,從一種口味都沒有到所有口味全有

這個狀態用數組dp[1<<M]來記錄,1<<M代表1左移M位=2^M

用s[i]記錄每包糖果的狀態,例如10101,代表該包糖果能有1,3,5號口味

代碼如下:

#include<iostream>
using namespace std;
int n,m,k;

int main()
{
	cin>>n;
	cin>>m;
	cin>>k;
	
	int s[n+1];
	int dp[1<<m];
	for(int i=0;i<(1<<m);i++)
		dp[i]=-1;
	for(int i=1;i<=n;i++)
	{
		int ss=0;
		int t;
		for(int j=1;j<=k;j++)
		{
			//該循環中,用ss和或運算,來記錄該包糖果所能產生的狀態,並存入s[i]數組中
			//同時用dp數組記錄下該包糖果的狀態
			//dp[ss]=1 代表着該狀態可由一包糖果達到 
			cin>>t;
			ss|=1<<(t-1);
		}
			
		
		s[i]=ss;
		dp[ss]=1;
		
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=(1<<m)-1;j++)
		{
			//判斷當前狀態是否可達到 
			//實際上用來跳過一些只有0或幾種口味的狀態,即跳過dp[0],dp[1]等 
			if(dp[j]==-1)continue;
			//若該狀態可達 
			if(dp[j|s[i]]==-1) 
			//在該狀態dp[j]的基礎上,逐個篩選加上每個糖果後的狀態,如目標狀態未達到,則讓其達到 
			dp[j|s[i]]=dp[j]+dp[s[i]];
			else
			//若目標狀態已達到,則選取更小的 
			dp[j|s[i]]=min(dp[j|s[i]],dp[j]+dp[s[i]]);
		}
	}
	cout<<dp[(1<<m)-1];
	
}

 

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