Mega Man’s Missions

Mega Man’s Missions

Mega Man is off to save the world again. His objective is to kill the Robots created by Dr. Wily whose motive is to conquer the world. In each mission, he will try to destroy a particular Robot. Initially, Mega Man is equipped with a weapon, called the “Mega Buster” which can be used to destroy the Robots.  Unfortunately, it may happen that his weapon is not capable of taking down every Robot. However, to his fortune, he is capable of using the weapons from Robots which he has completely destroyed and these weapons maybe able to take down Robots which he otherwise cannot with his own weapon. Note that, each of these enemy Robots carry exactly one weapon themselves for fighting Mega Man.  He is able to take down the Robots in any order as long as he has at least one weapon capable of destroying the Robot at a particular mission. In this problem, given the information about the Robots and their weapons, you will have to determine the number of ways Mega Man can complete his objective of destroying all the Robots.

 

Input

Input starts with an integer T(T≤50), the number of test cases.

Each test case starts with an integer N(1≤N≤16). Here N denotes the number of Robots to be destroyed (each Robot is numbered from 1 to N). This line is followed by N+1 lines, each containing N characters. Each character will either be ‘1’ or ‘0’. These lines represent a (N+1)*N matrix. The rows are numbered from 0 to N while the columns are numbered from 1 to N. Row 0 represents the information about the “Mega Buster”. The jth character of Row 0 will be ‘1’ if the “Mega Buster” can destroy the jthRobot. For the remaining N rows, the jth character of ith row will be ‘1’ if the weapon of ith Robot can destroy the jth Robot. Note that, a Robot’s weapon could be used to destroy the Robot itself, but this will have no impact as the Robot must be destroyed anyway for its weapon to be acquired.

Output

For each case of input, there will be one line of output. It will first contain the case number followed by the number of ways Mega Man can complete his objective. Look at the sample output for exact format.

 

Sample Input

Sample Output

3

1

1

1

2

11

01

10

3

110

011

100

000

 

Case 1: 1

Case 2: 2

Case 3: 3

 

 

译:

[Description]

洛克人又来拯救世界了。他的目的是杀死 Wily 博士做的机器人。在这个任务里,他将要试
着摧毁一些机器人。
一开始,洛克人有一个叫巨型炸弹的武器,可以用来摧毁一个的机器人。
不幸的是,一个武器只能打倒一些特定机器人。
然而,幸运的是,他可以使用他已经摧毁了的机器人的武器。
注意,每个带武器的机器人只会带一个武器。 洛克人身上只要有武器就能打到一个特定的机
器人。
在这个问题中,告诉你关于机器人及其武器的信息,你需要计算出洛克人完成任务的顺序的
方案数。
(原文题意有点生涩,为了理解,有些地方稍微改了下)
(算了,说不清楚了,再说说大意:一开始你有一个武器,然后每个机器人也有一个武器,
所有的武器都可以摧毁一些特定的机器人, 你可以得到你摧毁的机器人身上的武器。 问消灭
所有机器人的方案数是多少,即有多少种不同的顺序)

[Input]

第一行一个整数 T,表示 T 组数据。
对于每组数据第一行一个整数 N,表示 N 个机器人(编号从 1 到 N) ,
接下来 N+1 行每行 N 个数字(0 或 1),即一个(N+1)*N 的矩阵,每个数字表示为 Cij,行号
从 0 到 N,列号从 1 到 N。
第 0 行代表武器巨型炸弹的信息 C0j,C0j 为 1 表示巨型炸弹可以摧毁第 j 个机器人。
接下来 N 行,Cij = 1 表示第 i 个机器人的武器可以摧毁第 j 个机器人。
注意, 一个机器人的武器可以用来摧毁自己, 但是这对题目没有什么影响,因为只有机器人
已经被摧毁了,洛克人才能得他的武器。

[Output]

对于每组数据输出一行,即洛克人摧毁机器人的顺序方案总数。

[Hint]

T <= 50, 1 <= N <=16
对于样例 3 如下顺序
武器状态(可以打的机器人)  一开始  第一次后  第二次后  第三次后
(1, 2, 3)            110    111      111      111
(1, 3, 2)            110    111      111      111
(2, 1, 3)            110    110      111      111
(2, 3, 1)            110    110      无法打 3
(3, 1, 2)            110    无法打 3
(3, 1, 2)            110    无法打 3
故答案为 3


/* 状压DP 看到了n的规模这么小,就知道可状态压缩解决了。

 |:按位或(有1则1)
 &:按位与(有0则0) 

 //i64d----->lld  !!!!!!!!!

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
/*
	状压DP 
	|:按位或(有1则1)
	&:按位与(有0则0) 
	//WA 不会写啊~~~~~~ 
	//又WA~~~~~~~~~ 
	//i64d----->lld  !!!!!!!!!
*/
const int maxn=1<<17;
long long dp[maxn],n;
int KILL[20];

void pre()
{
	for(int j=0;j<maxn;j++) dp[j]=-1;
	for(int i=0;i<20;i++)	KILL[i]=0;
}

void readdate()//预处理 
{
	scanf("%d",&n);
	string str;
	for(int i=0;i<=n;i++)
	{
		cin>>str;
		int a=1;
		int len=str.size();
		for(int j=0;j<len;j++)
		{
			if(str[j]=='1') KILL[i]+=a;
				a=2*a;
		}
	}
}

long long  DP(int sta)//记忆化搜索 
{
	if(sta+1==(1<<n)) return 1;
	if(dp[sta]!=-1) return dp[sta];
	long long ans=0;
	int kill=KILL[0];

	for(int i=0;i<n;i++)
		if((sta&(1<<i))>0)
			kill=(kill|KILL[i+1]);

	for(int i=0;i<n;i++)
		if(((sta&(1<<i))==0)&&((kill&(1<<i))>0))
			ans+=DP((sta+(1<<i)));

	return dp[sta]=ans;
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		pre();
		readdate();
		printf("Case %d: %lld\n",i,DP(0));
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值