HDU ACM Eight
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043
解题背景:
看到八数码问题,没有任何的想法,偶然在翻看以前做的题的时候发现解决过类似的一道题,不过那题是求最长的移动步骤,给你的时间有10s之多,用set和queue过了它,这题我套用当时的模板,具体解题点击这里,发现TLE了一辈子。后来直接敲了一遍lrj白书上关于八数码的代码,还是TLE,一天就这样过去了,决定看别人的思路,很快就找到Kuangbin神的代码,代码思路基本相似,只是哈希函数的差别,TLE的原因没其他,卡就卡你的哈希,搜索了多份代码,反复地提到了康托展开,百度之后决定搞懂其。
百度之后发现其只是给你介绍什么是康托展开,然后告诉你康托展开可以用代码实现,然后他就将其用代码展示予你看。||- _ -
康托展开可以看做是特殊的哈希函数,而且是不会产生冲突,固定位数的数在排列组合中得到的数按大小比较的话都有一个特定的位置,康托展开就是计算这个数在当中的排列位置,百度中你会看见:(只是想说清楚这段文字和实现代码的关系)

其举的第二个例子中,即判断1324在排列数中是第几大的数,有一个式子的模型是:X * Y!,X表示当前数到的位数其后面的数有几个比其小,Y跟此时数到的位数有关,其值是这个排列数的总的位数减去当前数到的位数,即剩下来有几位,Y!的意义是剩下的位数进行排列组合,而X表示有几个数能替代当前数到的位数当前的数,比如说刚数到第一个数时,这里表示能替代1的数有几个(比1小的数),因为你的目的是看这个排列数是第几大的数。对于1324中的1来说为0个;这时只是处理了第一个位置的位数,接下来从左往后还有需要数到的位数,Y也依次减一。最终累加的数才能得出在排列数是第几大的数。实现的代码将这些阶乘都先计算出来。
用此为哈希函数个人感觉有点像位运算通过二进制得到独一无二的数,学习ing。
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#define MAXN 1000003
#define SIZE 9
using namespace std; typedef int State[SIZE];
int dir[][] = {{, -}, {, }, {-, }, {, }};
string dirFlag[] = {"l", "r", "u", "d"};
State st[MAXN], goal = {,,,,,,,,};
string dist[MAXN];
int head[MAXN], next[MAXN]; int hash(State& s)
{
int v = ;
for(int i=; i<SIZE; ++i) v = v* + s[i];
return v%MAXN;
} int try_to_insert(int s)
{
int h = hash(st[s]);
int u = head[h];
while(u)
{
if(memcmp(st[u], st[s], sizeof(st[s])) == ) return ;
u = next[u];
}
next[s] = head[h];
head[h] = s;
return ;
} int Traverse()
{
memset(head, , sizeof(head));
int front = , rear = ;
dist[front] = "";
while(front < rear)
{
State& s = st[front];
if(memcmp(goal, s, sizeof(s)) == ) return front;
int z;
for(z=; z<SIZE; ++z) if(!s[z]) break;
int x = z/, y = z%;
for(int d=; d<; ++d)
{
int newx = x + dir[d][];
int newy = y + dir[d][];
int newz = newx * + newy;
if(newx >= && newx < && newy >= && newy < )
{
State& t = st[rear];
memcpy(&t, &s, sizeof(s));
t[newz] = s[z];
t[z] = s[newz];
dist[rear].assign(dist[front]);
dist[rear].append(dirFlag[d]);
if(try_to_insert(rear)) rear++;
}
}
front++;
}
return ;
} int main()
{
freopen("F:\\test\\input.txt", "r", stdin);
char ch;
while(cin>>ch)
{
if(ch == 'x') st[][] = ;
else st[][] = ch - '';
for(int i=; i<SIZE; ++i)
{
cin>>ch;
if(ch == 'x') ch = '';
st[][i] = ch - '';
}
int ans = Traverse();
if(ans > ) cout<<dist[ans]<<endl;
else cout<<"unsolvable"<<endl;
}
return ;
}
TLE 代码
WA的原因:
如果按照普通的想法来做,一般就像我刚看到题所想到,每一个case都去遍历一遍,每一次都去判段能不能走通这条路,因为是从不定的情况到确定的情况,如果是不可能走通的情况,那么每个case消耗的时间都是最大的,所以TLE是不可避免了。相反,从反过来的情况去判断,一次就能记录下来所有不能达到的情况和记录可以到达情况的步骤。傻傻的就这样想不通,这样我想起了很久之前做的一道题,每个Case都去筛素数.....隔了那么长的时间,思维却丝毫没有改变,嗒嗒
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<queue>
#define MAXN 362888
#define SIZE 9
using namespace std; typedef int State[SIZE];
int dir[][] = {{, -}, {, }, {-, }, {, }};
char dirFlag[] = "rldu"; typedef struct Status{
State value;
}Status; queue<Status>queuing; string st[MAXN];
bool visit[MAXN]; int factory[] = {, , , , , , , , , };
const int start = ;
int aim = ;
int input[SIZE]; int try_to_insert(int s[])
{
int sum = ;
for(int i=; i<SIZE; ++i)
{
int cnt = ;
for(int j=i+; j<SIZE; ++j)
if(s[i]>s[j]) ++cnt;
sum += cnt*factory[SIZE-i-];
}
return sum;
} void Traverse()
{
memset(visit, false, sizeof(visit));
Status init;
for(int i=; i<SIZE-; ++i) init.value[i] = i+;
init.value[SIZE-] = ;
visit[start] = true;
st[start] = "";
queuing.push(init);
while(!queuing.empty())
{
Status ss = queuing.front();
State& s = ss.value;
queuing.pop();
int z;
for(z=; z<SIZE; ++z) if(!s[z]) break;
int x = z/, y = z%;
for(int d=; d<; ++d)
{
int newx = x + dir[d][];
int newy = y + dir[d][];
int newz = newx * + newy;
if(newx >= && newx < && newy >= && newy < )
{
Status tt;
State& t = tt.value;
memcpy(t, s, sizeof(s));
t[newz] = s[z];
t[z] = s[newz];
int elem = try_to_insert(s);
int adr = try_to_insert(t);
if(!visit[adr])
{
visit[adr] = true;
st[adr] = dirFlag[d] + st[elem];
queuing.push(tt);
}
}
}
}
return;;
} int main()
{
// freopen("F:\\test\\input.txt", "r", stdin);
char ch;
Traverse();
while(cin>>ch)
{
if(ch == 'x') input[] = ;
else input[] = ch - '';
for(int i=; i<SIZE; ++i)
{
cin>>ch;
if(ch == 'x') ch = '';
input[i] = ch - '';
}
aim = try_to_insert(input);
if(visit[aim]) cout<<st[aim]<<endl;
else cout<<"unsolvable"<<endl;
}
return ;
}
HDU ACM Eight的更多相关文章
- hdu acm 1028 数字拆分Ignatius and the Princess III
Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...
- hdu acm 1166 敌兵布阵 (线段树)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- hdu acm 2082 找单词
找单词 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- HDU ACM 1325 / POJ 1308 Is It A Tree?
Is It A Tree? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- HDU ACM 1134 Game of Connections / 1130 How Many Trees?(卡特兰数)
[题目链接]http://acm.hdu.edu.cn/showproblem.php?pid=1134 [解题背景]这题不会做,自己推公式推了一段时间,将n=3和n=4的情况列出来了,只发现第n项与 ...
- HDU ACM 题目分类
模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 104 ...
- HDU ACM 1690 Bus System (SPFA)
Bus System Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- HDU ACM 1224 Free DIY Tour (SPFA)
Free DIY Tour Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- HDU ACM 1869 六度分离(Floyd)
六度分离 Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
随机推荐
- 40. Combination Sum II
题目: Given a collection of candidate numbers (C) and a target number (T), find all unique combination ...
- 第三章:推荐系统冷启动与CB
3.1冷启动问题简介: 冷启动问题(cold start)主要分三类: • 用户冷启动 • 物品冷启动 • 系统冷启动 参考解决方案: • 推热门 • 利用用户 ...
- OpenCV码源笔记——Decision Tree决策树
来自OpenCV2.3.1 sample/c/mushroom.cpp 1.首先读入agaricus-lepiota.data的训练样本. 样本中第一项是e或p代表有毒或无毒的标志位:其他是特征,可以 ...
- jpa-hibernate配置转换
persistence.xml spring-demo-cfg.xml hibernate配置文件 Spring Data JPA:为简化JPA的开发提供帮助.EntityManager的创建与销毁. ...
- 1218. Episode N-th: The Jedi Tournament(bfs)
1218 简答题 对于当前点 判断每个点是否可达 #include <iostream> #include<cstdio> #include<cstring> #i ...
- 自己遇到的Android虚拟机出现的错误及解决方法【不断更新】
2012.11.9 第一个: [2012-11-09 13:15:14 - Tesa] Android Launch! [2012-11-09 13:15:14 - Tesa] The connect ...
- django访问静态文件
DJANGO 1.6 静态文件处理 添加 STATICFILES_DIRS = (os.path.abspath('static'),) 新建static目录
- angular js 实例参数学习
<!DOCTYPE html> <html> <head> <meta name="description" content=" ...
- RESTful API 设计最佳实践(转)
背景 目前互联网上充斥着大量的关于RESTful API(为方便,下文中“RESTful API ”简写为“API”)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API 格式如何?你的 ...
- 云计算服务模型,第 1 部分: 基础架构即服务(IaaS)
英文原文:Cloud computing service models, Part 1: Infrastructure as a Service 本文介绍三个云类别中的第一个:基础架构即服务(infr ...