uva 11795 洛克人的难题

非常好的题目

题意:给定一个初始武器,可以消灭编号1-i的人

每消灭一个机器人,获得其武器。

求总共可以有多少种方法消灭所有的机器人

 

状态描述:    State[i]  在已经消灭了i二进制表示的机器人的情况下,对应的武器的情况

                        以第三组数据为例 State[0] 表示在0 0 0 即三个机器人都没有消灭的情况下 state[0] == 3 即 0 1 1 可以消灭到

                        第1个或者第2个机器人

                       每个状态i只和其前面的状态有关(非常重要),所以状态转移方程如下

                       dp[i] = 将i的某一位1的二进制位置为0以后且满足该State可以转移到目前状态 的 dp[i-1]...dp[0]的和

 

                        结论为dp[(1 << n) - 1] 即 所有的敌人都被消灭置为1的数目和

 

#include <iostream>
#include <vector>
#include <map>
#include <list>
#include <set>
#include <deque>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <iomanip>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
#include <queue>
using namespace std;

///宏定义
const int INF = 20000000;
const int maxn = 1<<17;
///全局变量 和 函数
//
int T;
int n;
long long dp[maxn];
int weapons[maxn];
int State[maxn];
char s[30];
int main()
{
	//	
	int i, j;
	scanf("%d", &T);
	int cases = 1;
	while (T--)
	{
		memset(dp, 0, sizeof(dp));
		memset(weapons, 0, sizeof(weapons));
		memset(State, 0, sizeof(State));
		scanf("%d", &n);
		for (i = 0; i <= n; i++)
		{
			scanf("%s", s);
			for (j = 0; j < strlen(s); j++)
			{
				if ((s[j] - '0') != 0)
				{
					weapons[i] |= (1 << j);
				}
			}
		}
		State[0] = weapons[0];
		for (i = 0; i < (1 << n); i++)
		{
			State[i] = State[0];
			for (j = 0; j < n; j++)
			{
				//如果在本状态中第j个人被杀,取得其武器
				if ((1 << j) & i)
				{
					State[i] |= weapons[j + 1];
				}
			}
		}

		dp[0] = 1;
		for (i = 1; i < (1 << n); i++)
		{
			dp[i] = 0;
			for (j = 0; j < n; j++)
			{
				//如果当前位置为1,说明该位置机器人已经被消灭,把该位置放置为0,并且查看该状态是否可以转移到此状态
				//i ^ (1 << j) 把当前状态对应1返回为0, 取state数组查看该状态是否可以转移(即杀到当前位置机器人人)
				// 所以  & (1 << j) 查看对应位置是否为1
				if (  (i & (1 << j)) &&  (State[i ^ (1 << j)] & (1 << j))      )
				{
					dp[i] += dp[i ^ (1 << j)];
				}
			}
		}

		printf("Case %d: %lld\n", cases++, dp[(1 << n) -1]);

	}


	return 0;
}


 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值