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 ...
随机推荐
- C#通过代码注册COM组件
using System; using System.Diagnostics; using Microsoft.Win32; namespace ChuckLu.Utility { public cl ...
- [Codeforces137C]History(排序,水题)
题目链接:http://codeforces.com/contest/137/problem/C 题意:给n对数,分别是一个事件的起始和终止时间.问被有几个事件被其他事件包含. 思路:先排序,按照起始 ...
- [Codeforces676B]Pyramid of Glasses(递推,DP)
题目链接:http://codeforces.com/problemset/problem/676/B 递推,dp(i, j)表示第i层第j个杯子,从第一层开始向下倒,和数塔一样的题.每个杯子1个时间 ...
- 函数lock_rec_set_nth_bit
lock 分配内存 lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes); 内存分配图 0xxx 2 xxx 0xxx3 ...
- RecyclerView 结合 CardView 使用(二)
上一篇的基础上,修改了,CardView的布局和点击效果 总结: CardView的奇葩属性 :app:cardPreventCornerOverlap="false" 和园角边框 ...
- angular js 指令的数据传递 及作用域数据绑定
<div my-directive my-url="http://google.com" my-link-text="Click me to go to Googl ...
- 深入学习Oracle分区表及分区索引
关于分区表和分区索引(About Partitioned Tables and Indexes)对于10gR2而言,基本上可以分成几类: • Range(范围)分区 • Has ...
- db2数据库sql报错信息
sqlcode sqlstate 说明 000 00000 SQL语句成功完成 01xxx SQL语句成功完成,但是有警告 +012 01545 未限定的列名被解释为一个有相互关系的引用 +098 ...
- SVN版本管理提示信息
1. FAQ 1.路径或权限不足时将出现错误信息提示: http://192.134.4.251/svn/svnproject(路径不对)Error * PROPFIND request failed ...
- 【转】Android开发学习笔记:5大布局方式详解
Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(Tabl ...