题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2209
题意:说给一个,长度不超过20的01串。表示纸牌的正反面。
每反过来一张纸牌,其相邻的纸牌也要反过来。当然,两端的纸牌的翻转只影响其相邻的一张牌。
问,最少多少步才能使全部的牌都成为正面,也就是说,该串全部位0。
思路:
我们可以看到,最多才20张牌。所以,应该可以想到2进制压缩。(对于没有学过状态压缩的,可能想不到)。
把该串作为一个数的二进制来看。就很easy了。当该数变为0,也就是最终状态了。。
Code:
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 21;
const int M = 1 << 21;
bool hash[M];
int x;
char str[N];
struct Node{
int num;// are you kiding me. yeah, char is one bit. int is four..so you RE.
int step;
Node(){}
Node(int s, int d){
num = s;
step = d;
}
};
int ToInt(char *s){
int ans = 0, len = strlen(s), k = 1;
for(int i = len - 1; i >= 0 ;i --){
ans += (s[i] - '0') * k;
k = k * 2;
}
return ans;
}
void bfs(){
memset(hash, 0, sizeof(hash));
int len = strlen(str);
queue<Node> q;
q.push(Node(x, 0));
hash[x] = true;
while(!q.empty()){
Node now = q.front();
q.pop();
int k;
if(now.num == 0){
printf("%d\n",now.step);
return ;
}
// printf("now = %d\n", now.num);
for(int i = 0; i < len - 1; i ++){
k = now.num;
if(i == 0){
k = k ^ 3;
}
else k = k ^ (7 << (i - 1));
if(!hash[k]){
q.push(Node(k, now.step + 1));
hash[k] = true;
}
}
k = now.num;
k = k ^ ((1 << (len - 1)) + (1 << (len - 2)));
if(!hash[k]){
q.push(Node(k, now.step + 1));
hash[k] = true;
}
}
puts("NO");
return ;
}
int main(){
while(~scanf("%s", str)){
x = ToInt(str);
if(x == 0){
puts("0");
continue;
}
if(x == 1 && strlen(str) == 1){
puts("1");
continue;
}
bfs();
}
return 0;
}
状态压缩是一个应该学习一下的点。。可以参看一下学长们的总结。。