Mega Man‘s Mission
Mega Man is off to save theworld again. His objective is to kill the Robots created by Dr.Wily whose motive is
to conquer the world. In each mission, he willtry to destroy a particular Robot. Initially, Mega Man is equippedwith a weapon, called the “Mega Buster”which canbe used to destroy theRobots. Unfortunately, it mayhappen that his weapon is not
capable of taking down every Robot.However, to his fortune, he is capable of using the weapons fromRobots which he has completelydestroyed and these weapons maybe able to takedown Robots which he otherwise cannot with his own weapon. Notethat,
each of these enemy Robots carryexactly one weapon themselvesfor fighting Mega Man. He isable to take down the Robots in any order as long as he has atleast one weapon capable of destroying the Robot at a particularmission. In this problem,
given the information about the Robotsand their weapons, you will have to determine the number of waysMega Man can complete his objective of destroying all theRobots.
Input
Input starts with aninteger T(T≤50), thenumber of test cases.
Each test case starts with aninteger N(1≤N≤16).Here N denotes
thenumber of Robots to be destroyed (each Robot is numbered from 1to N). This line is followedby N+1 lines,eachcontaining N characters.Each
character will eitherbe ‘1’ or ‘0’.These lines representa (N+1)*N matrix.The rows are numbered from 0to N while
thecolumns are numbered from 1 to N.Row 0 represents the information about the “MegaBuster”.The jth characterof Row 0 willbe ‘1’ ifthe “Mega
Buster” can destroythe jth Robot.For theremaining N rows,the jth characterof ith rowwill
be ‘1’ if the weaponof ith Robotcan destroythe jth Robot.Note that, a Robot’s weapon could be
used to destroy the Robotitself, but this will have no impact as the Robot must be destroyedanyway for its weapon to be acquired.
Output
For each case of input, there will be one lineof output. It will first contain the case number followed by thenumber of ways Mega
Man can complete his objective. Look at thesample output for exact format.
Sample Input
3
1
1
1
2
11
01
10
3
110
011
100
000
SampleOutput
Case 1: 1
Case 2: 2
Case 3: 3
题意: 洛克人最初只有一种武器 “Mega Buster”(这种武器可以消灭特定的一些机器人),你需要按照一定的顺序消灭 n 个其他机器人。每消灭一个机器人你将会得到他的武器(也可能没有得到武器),而这些武器可以消灭特定的机器人。你的任务是计算出消灭所有机器人的顺序总数。注意:一个机器人的武器可能可以消灭自己,但这对最终答案没有影响,因为必须先消灭这个机器人才能够得到他的武器。
思路:n 的范围为 [1,16],可以用状态压缩DP来做,用二进制保存状态。时间复杂度为 O(n*2^n) 。首先用 weapon 数组保存杀死这个机器人能得到的武器,用二进制表示,第i位为 1 表示可以杀死第 i 个机器人,为 0 则不可以。其中 weapon[0] 表示原始拥有的武器 (也就是 “Mega Buster” )。用集合 st 来表示杀了的机器人,二进制的1即为杀死了了,0即为没杀死,在该状态下所拥有的武器(所有状态下的初始武器都是
weapon[0] ),用 attack 数组保存所有状态。用 dp[st] 表示在状态为 st 时所有的顺序方案总数。 那么状态转移怎么写呢,
首先,对于每一种状态,我们预处理一下这个状态下可以干掉哪些机器人,这样才能转移,然后对于一个状态 st 来说,要干掉第 i 个机器人,则要从没干掉 i 的状态里面转移,即 s^(1<<i)。
则 dp[s] = sum(dp[s^(1<<i)]) ,条件为 s&(1<<i) 而且 attack[s^(1<<i)] 可以干掉 i。
把 st 里面的所有 1 枚举一次,再加起来即可。
当所有机器人都不杀死的方案总数为 1 , 即 dp[0] = 1 .
<span style="font-size:18px;">#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <string> #include <algorithm> #include <queue> #include <stack> using namespace std; #define ll long long const double PI = acos(-1.0); const double e = 2.718281828459; const double eps = 1e-8; const int MAXN = (1<<16)+10; int weapon[MAXN]; // 保存每个机器人可以杀死的机器人 int attack[MAXN]; // 保存每个状态可以杀死的机器人 ll dp[MAXN]; // 2 的 16 次方会爆 int。 // 用来统计每种状态的顺序方案种数 char s[20]; int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int Case, n; int num = 1; cin>>Case; while(Case--) { cin>>n; for(int i = 0; i <= n; i++) { scanf("%s", s); weapon[i] = 0; for(int j = 0; j < n; j++) { if(s[j] == '1') weapon[i] |= 1<<j; } //cout<<i<<" "<<weapon[i]<<endl; } int total = (1<<n)-1; for(int st = 0; st <= total; st++) { attack[st] = weapon[0]; for(int i = 1; i <= n; i++) { int j = i-1; if(st&(1<<j)) { //如果该状态可以杀死 i,那么该状态也可以杀死i所能干掉的 attack[st] |= weapon[i]; } } //printf("%d %d\n", st, attack[st]); } memset(dp, 0, sizeof(dp)); dp[0] = 1; for(int st = 1; st <= total; st++) { for(int i = 0; i < n; i++) { if(st&(1<<i)) // 如果 st 的这种状态能够杀死 i { // 那么 st 由不能杀死 i 的状态转移过来, 即st^(1<<i) if(attack[st^(1<<i)]&(1<<i)) { // 并且要求 st^(1<<i) 这种状态要能够杀死 i dp[st] += dp[st^(1<<i)]; } } } //printf("%d %d\n", st, dp[st]); } printf("Case %d: %lld\n", num++, dp[total]); } return 0; } </span>
UVa11795 Mega Man's Mission(状态压缩DP)