题目大意:

有一堆积木,0号节点每次可以和其上方,下方,左上,右下的其中一个交换,问至少需要多少次达到目标状态,若步数超过20,输出too difficult

目标状态:

0

1 1

2 2 2

3 3 3 3

4 4 4 4 4

5 5 5 5 5 5

题目分析:

因为前段时间做了一道转花盆刻骨铭心,所以一看到这题就开始bfs+hash,明知道过不了,但谁知道姿势正确得了85分,后来出题人告诉数据最大步数才14,我把搜索停止条件改成了18,瞬间ac。。。

正解有很多种:迭代加深,双向搜索,\(A^{*}\)……

考后写了一下迭代加深,不是一般的快,具体讲解请百度骑士.

code

bfs + hash + 玄学剪枝

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
namespace IO{
inline int read(){
int i = 0, f = 1; char ch = getchar();
for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
if(ch == '-') f = -1, ch = getchar();
for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
return i * f;
}
inline void wr(ll x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
}using namespace IO; const int N = 10, M = 30;
int T, bin[N], ans;
char initMap[M];
struct node{char s[M]; int cnt;};
queue<node> que; bool flag;
typedef unsigned long long ull;
ull desVal;
const int Mod = 233333, H = 31;
vector<ull> G[Mod + 5];
vector<int> used; inline bool insert(ull x){
int key = x % Mod;
for(int i = 0; i < G[key].size(); i++)
if(G[key][i] == x) return false;
G[key].push_back(x); used.push_back(key); return true;
} inline ull toHash(char s[M]){
ull ret = 0;
for(int i = 1; i <= 21; i++) ret = ret * H + s[i] - '0';
return ret;
} inline void init(){
bin[0] = 0;for(int i = 1; i <= 6; i++) bin[i] = bin[i - 1] + i;
for(int i = 1; i <= 6; i++)
for(int j = 1; j <= i; j++)
desVal = desVal * H + i - 1;
} inline pair<int, int> get0Pos(char s[M]){
pair<int, int> ret;
for(int i = 1; i <= 6; i++)
for(int j = 1; j <= i; j++)
if(s[bin[i - 1] + j] == '0') {ret.first = i, ret.second = j; return ret;}
} inline void add(char s[M], int cnt){
node tmp;
for(int i = 1; i <= 21; i++) tmp.s[i] = s[i];
tmp.cnt = cnt;
que.push(tmp);
} int main(){
T = read(); init();
while(T--){
for(int i = 0; i < used.size(); i++) G[used[i]].clear();
flag = false; ans = 0;
for(int i = 1; i <= 6; i++)
for(int j = 1; j <= i; j++) initMap[bin[i - 1] + j] = read() + '0';
ull hashVal = toHash(initMap);
if(hashVal == desVal){
wr(0); putchar('\n');
continue;
}
insert(hashVal);
while(!que.empty()) que.pop();
add(initMap, 0);
while(!que.empty()){
char now[M];
node tmp = que.front();
int cnt = tmp.cnt;
for(int i = 1; i <= 21; i++) now[i] = tmp.s[i];
pair<int, int> pos = get0Pos(now);
//leftup
if(pos.second != 1){
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first - 1] + pos.second - (bin[pos.first] - bin[pos.first - 1])]);
ull hashVal = toHash(now);
if(hashVal == desVal){flag = true, ans = cnt + 1; break;}
else if(cnt + 1 == 18) break;
if(insert(hashVal)) add(now, cnt + 1);
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first - 1] + pos.second - (bin[pos.first] - bin[pos.first - 1])]);
}
//up
if(pos.second != bin[pos.first] - bin[pos.first - 1]){
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first - 1] + pos.second - (bin[pos.first] - bin[pos.first - 1]) + 1]);
ull hashVal = toHash(now);
if(hashVal == desVal){flag = true, ans = cnt + 1; break;}
else if(cnt + 1 == 18) break;
if(insert(hashVal)) add(now, cnt + 1);
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first - 1] + pos.second - (bin[pos.first] - bin[pos.first - 1]) + 1]);
}
//down
if(pos.first != 6){
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first] + pos.second]);
ull hashVal = toHash(now);
if(hashVal == desVal){flag = true, ans = cnt + 1; break;}
else if(cnt + 1 == 18) break;
if(insert(hashVal)) add(now, cnt + 1);
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first] + pos.second]);
}
//rightdown
if(pos.first != 6){
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first] + pos.second + 1]);
ull hashVal = toHash(now);
if(hashVal == desVal){flag = true, ans = cnt + 1; break;}
else if(cnt + 1 == 18) break;
if(insert(hashVal)) add(now, cnt + 1);
swap(now[bin[pos.first - 1] + pos.second], now[bin[pos.first] + pos.second + 1]);
}
que.pop();
}
if(flag) wr(ans), putchar('\n');
else printf("too difficult\n");
}
return 0;
}

迭代加深

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
namespace IO{
inline int read(){
int i = 0, f = 1; char ch = getchar();
for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
if(ch == '-') f = -1, ch = getchar();
for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
return i * f;
}
inline void wr(ll x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
}using namespace IO; const int N = 10, M = 30;
int T, ans;
int initMap[N][N];
bool flag;
typedef pair<int, int> P;
P pos;
const int des[N][N] = {{0}, {0, 0},{0,1,1},{0,2,2,2},{0,3,3,3,3},{0,4,4,4,4,4},{0,5,5,5,5,5,5}}; inline int H(){
int ret = -1;
for(int i = 1; i <= 6; i++)
for(int j = 1; j <= i; j++) if(initMap[i][j] ^ des[i][j]) ret++;
return ret;
} inline bool dfs(int now, int dep, int x, int y){
if(now > dep){
if(H() == -1) return true;
else return false;
}
if(H() + now - 1 > dep) return false;
//leftUp
if(y != 1){
swap(initMap[x][y], initMap[x - 1][y - 1]);
if(dfs(now + 1, dep, x - 1, y - 1)) return true;
swap(initMap[x][y], initMap[x - 1][y - 1]);
}
//up
if(y != x){
swap(initMap[x][y], initMap[x - 1][y]);
if(dfs(now + 1, dep, x - 1, y)) return true;
swap(initMap[x][y], initMap[x - 1][y]);
}
//down
if(x != 6){
swap(initMap[x][y], initMap[x + 1][y]);
if(dfs(now + 1, dep, x + 1, y)) return true;
swap(initMap[x][y], initMap[x + 1][y]);
}
//rightdown
int tmp = 0;
for(int i = 1; i < x; i++) tmp += i;
if(x != 6){
swap(initMap[x][y], initMap[x + 1][y + 1]);
if(dfs(now + 1, dep, x + 1, y + 1)) return true;
swap(initMap[x][y], initMap[x + 1][y + 1]);
}
return false;
} int main(){
T = read();
while(T--){
ans = 0, flag = false;
for(int i = 1; i <= 6; i++)
for(int j = 1; j <= i; j++) {
scanf("%d", &initMap[i][j]);
if(!initMap[i][j]) pos = P(i, j);
}
// cout<<pos.first<<" "<<pos.second<<endl;
for(int i = 0; i <= 20; i++)
if(dfs(1, i, pos.first, pos.second)){flag = true, ans = i;break;}
if(flag) wr(ans), putchar('\n');
else printf("too difficult\n");
}
return 0;
}

NOIP 模拟 玩积木 - 迭代加深搜索 / bfs+hash+玄学剪枝的更多相关文章

  1. HDU 1560 DNA sequence (IDA* 迭代加深 搜索)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1560 BFS题解:http://www.cnblogs.com/crazyapple/p/321810 ...

  2. 【bzoj1085】【 [SCOI2005]骑士精神】启发式剪枝+迭代加深搜索

    (上不了p站我要死了,侵权度娘背锅) 如果这就是启发式搜索的话,那启发式搜索也不是什么高级玩意嘛..(啪啪打脸) Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且 ...

  3. POJ1129Channel Allocation[迭代加深搜索 四色定理]

    Channel Allocation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14601   Accepted: 74 ...

  4. BZOJ1085: [SCOI2005]骑士精神 [迭代加深搜索 IDA*]

    1085: [SCOI2005]骑士精神 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1800  Solved: 984[Submit][Statu ...

  5. 迭代加深搜索 POJ 1129 Channel Allocation

    POJ 1129 Channel Allocation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14191   Acc ...

  6. 迭代加深搜索 codevs 2541 幂运算

    codevs 2541 幂运算  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description 从m开始,我们只需要6次运算就可以计算出 ...

  7. UVA 529 - Addition Chains,迭代加深搜索+剪枝

    Description An addition chain for n is an integer sequence  with the following four properties: a0 = ...

  8. hdu 1560 DNA sequence(迭代加深搜索)

    DNA sequence Time Limit : 15000/5000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total ...

  9. 迭代加深搜索 C++解题报告 :[SCOI2005]骑士精神

    题目 此题根据题目可知是迭代加深搜索. 首先应该枚举空格的位置,让空格像一个马一样移动. 但迭代加深搜索之后时间复杂度还是非常的高,根本过不了题. 感觉也想不出什么减枝,于是便要用到了乐观估计函数(O ...

随机推荐

  1. 无法显式调用运算符或访问器 错误处理方法 DLL study

    无法显式调用运算符或访问器 错误处理方法 转 无法显式调用运算符或访问器 错误处理方法 反汇编一个dll类库,导出的项目会报出很多bug,其中主要的就是“无法显式调用运算符或访问器”这个错误,看了一下 ...

  2. Codeforces Round 363 Div. 1 (A,B,C,D,E,F)

    Codeforces Round 363 Div. 1 题目链接:## 点击打开链接 A. Vacations (1s, 256MB) 题目大意:给定连续 \(n\) 天,每天为如下四种状态之一: 不 ...

  3. 用static 创建类的单例

    1.0 说明 通过函数调用new的static 类对象,由于static 对象只能初始化一次,由此构成单例运行. 2.0  直接代码 代码为windows,win32工程,因为只有一个文件,不上传工程 ...

  4. 设计模式--单例模式之Lock

    1.为什么用Lock及关键知识 当我们使用线程的时候,效率最高的方式当然是异步,即个个线程同时运行,其间互不依赖和等待.当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进 ...

  5. or小计

    1.使用or的时候,必须养成两边添加括号,否则结果完全不一样. 2.or条件如果复杂的情况下,可以适当考虑union all改写.

  6. FireBreath与JS交互1

    FireBreath提供接口供JS调用,提供的接口需要注册 必须在JSAPI对象的构造函数中注册,也就是 CxxxAPI::CxxxAPI()这个函数中调用 registerMethod(" ...

  7. 洛谷 P1709 隐藏口令Hidden Password

    ->题目链接 题解: 贪心+字符串 #include<iostream> #include<cstring> #define N 5000005 using namesp ...

  8. Json入门 分类: C_OHTERS 2014-04-23 16:20 601人阅读 评论(0) 收藏

    参考<疯狂android讲义>>730页 JSON的基础请参考W3SCHOOL的教程: http://www.w3school.com.cn/json/index.asp 例子: h ...

  9. 驱动程序调试方法之printk——自制proc文件(二)

    上一节的程序很振奋人心,我们自己实现了一个myprintk打印函数.但是这个函数存在一个致命的缺陷,那就是只能使用一次cat /proc/mymsg命令来读取mylog_buf的值.这是因为读到最后会 ...

  10. 【C++竞赛 G】Lines

    Time Limit: 3s Memory Limit: 64MB 问题描述 Ljr has several lines. The lines are covered on the X axis. L ...