题目链接: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的更多相关文章

  1. 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 ...

  2. hdu acm 1166 敌兵布阵 (线段树)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  3. hdu acm 2082 找单词

    找单词 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  4. 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 ...

  5. HDU ACM 1134 Game of Connections / 1130 How Many Trees?(卡特兰数)

    [题目链接]http://acm.hdu.edu.cn/showproblem.php?pid=1134 [解题背景]这题不会做,自己推公式推了一段时间,将n=3和n=4的情况列出来了,只发现第n项与 ...

  6. HDU ACM 题目分类

    模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 104 ...

  7. HDU ACM 1690 Bus System (SPFA)

    Bus System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  8. 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 ...

  9. HDU ACM 1869 六度分离(Floyd)

    六度分离 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

随机推荐

  1. swift:类型转换(is用作判断检测、as用作类型向下转换)

    类型转换是一种检查类实例的方式,并且哦或者也是让实例作为它的父类或者子类的一种方式.   类型转换在Swift中使用is 和 as操作符实现.这两个操作符提供了一种简单达意的方式去检查值的类型或者转换 ...

  2. Android The content of the adapter has changed but ListView did not receive a notification

    The content of the adapter has changed but ListView did not receive a notification. Make sure the co ...

  3. 2、@RequestMapping注解的用法

    @RequestMapping有如下属性值:

  4. apache缓存

    http://www.t086.com/article/4256 http://www.360doc.com/content/09/0928/13/41237_6551659.shtml

  5. twitter bootstrap 2.x 3.x区别

    栅格系统 (Grid system)说个我认为比较重要的,相对于RC 1中的3层,现在有4层了 We now have .col-xs (phones), .col-sm (tablets), .co ...

  6. 自动化:Appium运行成功,取得一个小的胜利

    看过乙醇大神的博文,然后又看了一些大神的博文,自己陆陆续续的折腾了一个月,今天上午的时候,appium终于跑起来了.纪念下,在自动化路上取得的一个小胜利 Appium版本:1.2 Python版本:2 ...

  7. [HIHO1184]连通性二·边的双连通分量(双连通分量)

    题目链接:http://hihocoder.com/problemset/problem/1184 题意裸,写个博客记下输出姿势. /* ━━━━━┒ギリギリ♂ eye! ┓┏┓┏┓┃キリキリ♂ mi ...

  8. 函数xdes_get_offset

    /********************************************************************//** Returns page offset of the ...

  9. uva1349Optimal Bus Route Design

    二分图最小权完美匹配. 一个最小费用流就能跑了,记住检查一下,容量是否跑满,如果没有跑满,就说明没有完美匹配. #include<cstdio> #include<algorithm ...

  10. js判断浏览器类型和内核

    function judge() { var sUserAgent = navigator.userAgent.toLocaleLowerCase(); var isLinux = (String(n ...