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;
}