UVA 1252 Twenty Question (集合DP,时间优化)

UVA 1252 Twenty Question (集合DP,时间优化)

用d(s,a)表示当前状体,集合s表示已询问的特征,集合a表示已询问的特征里面属于目标物w的特征,则集合a一定位s的子集。

每一次询问对应着状态的转移,则可得到状态转移方程:
d(s,a)=min(d(s,a),max(d(s+k,a+k),d(s+k,a))+1) ,k表示询问的特征。

当有且仅有一个物体满足a集合中的所有特征,而不满足{s}-{a}中的所有特征,那么此时d(s,a)=0。

有二项式定理可以得知,状态数有O(3m)个,每次状态转移有m种策略。所以对于dp的时间复杂度是O(m*3m)。

为了避免在每次状态转移时判断满足条件的物体数,我们可以通过预处理,将每个d(s,a)状态下的满足a集合中的所有特征,而不满足{s}-{a}中的所有特征的物体数求出,记录在cnt(s,a)中,时间复杂度是O(n*2m),对于dp的时间复杂度,这可以忽略不计。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int m,n;
int d[1<<11][1<<11];
int cnt[1<<11][1<<11];
int identity[130];
void init(void)
{
	memset(cnt,0,sizeof(cnt));
	memset(d,0x3f,sizeof(d));
	for(int i=0;i<(1<<m);i++)
	for(int j=0;j<n;j++)
	cnt[i][i&identity[j]]++;
}
int dp(int s,int a)
{
	if(d[s][a]!=INF)return d[s][a];
	if(cnt[s][a]==1)return d[s][a]=0;
	if(cnt[s][a]==2)return d[s][a]=1;
	for(int i=0;i<m;i++)
	if((s&(1<<i))==0)
		if(cnt[s|(1<<i)][a|(1<<i)]>=1&&cnt[s|(1<<i)][a]>=1)
		d[s][a]=min(d[s][a],max(dp(s|(1<<i),a|(1<<i)),dp(s|(1<<i),a))+1);
	return d[s][a];
}
void solve(void)
{
	init();
	printf("%d\n",dp(0,0));
}
int main(void)
{
//	freopen("out.txt","w",stdout);
	while(~scanf("%d%d",&m,&n)&&m)
	{
		memset(identity,0,sizeof(identity));
		string s;
		for(int i=0;i<n;i++)
		{
			cin>>s;
			for(int j=0;j<m;j++)
			if(s[j]=='1')identity[i]+=1<<j;
		}
		solve();
	}
//	fclose(stdout);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值