vijosP1016北京2008的挂钟 BFS + 优先队列
2013-01-03 23:31
627 查看
作为一个弱菜,第一次发题解报告,好紧张啊啊啊。。。
昨天闲的无聊,跑上vijos上瞧了瞧,发现vijos改版了,新版的vijos貌似很不错的样子,今天一高兴,在上面水了一天的题。。。
效率不是很高,卡了3个题。。。这个题就是第3个被卡的题。。。
题目链接:https://vijos.org/problems/P1016
题意很简单:有9个钟,每个钟表示4个时刻:12点,3点,6点,9点。现在有9种操作,每种操作分别将9个钟的某几个钟的时针顺时针旋转90度,问至少做哪几个操作,可以最快将9个钟变成12点,输出最少的操作序号,输出顺序类似字典序。
思想:看到此题,直接想到的就是BFS。由于有9个钟,每个钟有4种状态,所以一共有4^9种状态,只需要定义一个9维数组就可以判重,用bool型毫无压力。然后就是普通的BFS过程。不过写完一提交,10个点都TLE了。。。要加优化。很容易想到的是用优先队列优化,不过该用什么作为优先级呢,因为一时脑残,选错了优先级,开始了数小时的悲剧。。。一开始我选的是所有钟状态之和,和越小,越接近终点(终点是所有钟的状态都是0),后来好不容易改对了,可是运行出来的结果老长老长的,这才意识到有问题,果断继续改之。然后重新读了一下题,既然是要找操作数最少的,于是改用当前状态的操作数为优先级,然后测试样例,发现又有点问题,与样例输出的次序不一样。题目要求按类似字典序输出,然后在输出那里对答案数组排了个序再输出,因为这些操作与次序无关,就是说,从一个状态到另一个状态中间经过的操作,不管先执行哪个,都不影响最后的结果,所以BFS要找的就是最少的操作数,最后排个序就能达到题目要求了。
详情请见代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
bool flag[4][4][4][4][4][4][4][4][4];
int op[10][10] = {{0},{1,2,4,5},{1,2,3},{2,3,5,6},{1,4,7},{2,4,5,6,8},
{3,6,9},{4,5,7,8},{7,8,9},{5,6,8,9}};
int st[10];
struct node
{
int state[10];
int pos;//从起始状态到当前状态经过的操作数
int ans[200];//从起始状态到当前状态所有的操作
friend bool operator < (struct node a,struct node b)
{
return a.pos > b.pos;
}
}s,now;
void Bfs()
{
priority_queue<node> lcm;
int i,j;
memset(flag,0,sizeof(flag));
for(i = 1;i <= 9;i ++)
s.state[i] = st[i];
s.pos = 0;
flag[st[1]][st[2]][st[3]][st[4]][st[5]][st[6]][st[7]][st[8]][st[9]] = 1;
lcm.push(s);
while(!lcm.empty())
{
now = lcm.top();
lcm.pop();
for(i = 1;i <= 9;i ++)
{
s = now;
for(j = 0;op[i][j];j ++)
{
s.state[op[i][j]] ++;
if(s.state[op[i][j]] >= 4)
s.state[op[i][j]] -= 4;
// s.state[op[i][j]] %= 4;
}
if(!flag[s.state[1]][s.state[2]][s.state[3]][s.state[4]][s.state[5]][s.state[6]][s.state[7]][s.state[8]][s.state[9]])
{
s.ans[s.pos ++] = i;
flag[s.state[1]][s.state[2]][s.state[3]][s.state[4]][s.state[5]][s.state[6]][s.state[7]][s.state[8]][s.state[9]] = 1;
lcm.push(s);
}
if(!s.state[1] && !s.state[2] && !s.state[3] && !s.state[4] && !s.state[5]
&& !s.state[6] && !s.state[7] && !s.state[8] && !s.state[9])
{
// printf("%d",s.ans[0]);
sort(s.ans,s.ans + s.pos);//所有的操作互不干扰,无先后之分的
for(j = 0;j < s.pos;j ++)
printf("%d ",s.ans[j]);
printf("\n");
return;
}
}
}
}
int main()
{
int i,j;
while(scanf("%d",&j) != EOF)
{
st[1] = j;
for(i = 2;i <= 9;i ++)
{
scanf("%d",&st[i]);
}
Bfs();
}
return 0;
}
昨天闲的无聊,跑上vijos上瞧了瞧,发现vijos改版了,新版的vijos貌似很不错的样子,今天一高兴,在上面水了一天的题。。。
效率不是很高,卡了3个题。。。这个题就是第3个被卡的题。。。
题目链接:https://vijos.org/problems/P1016
题意很简单:有9个钟,每个钟表示4个时刻:12点,3点,6点,9点。现在有9种操作,每种操作分别将9个钟的某几个钟的时针顺时针旋转90度,问至少做哪几个操作,可以最快将9个钟变成12点,输出最少的操作序号,输出顺序类似字典序。
思想:看到此题,直接想到的就是BFS。由于有9个钟,每个钟有4种状态,所以一共有4^9种状态,只需要定义一个9维数组就可以判重,用bool型毫无压力。然后就是普通的BFS过程。不过写完一提交,10个点都TLE了。。。要加优化。很容易想到的是用优先队列优化,不过该用什么作为优先级呢,因为一时脑残,选错了优先级,开始了数小时的悲剧。。。一开始我选的是所有钟状态之和,和越小,越接近终点(终点是所有钟的状态都是0),后来好不容易改对了,可是运行出来的结果老长老长的,这才意识到有问题,果断继续改之。然后重新读了一下题,既然是要找操作数最少的,于是改用当前状态的操作数为优先级,然后测试样例,发现又有点问题,与样例输出的次序不一样。题目要求按类似字典序输出,然后在输出那里对答案数组排了个序再输出,因为这些操作与次序无关,就是说,从一个状态到另一个状态中间经过的操作,不管先执行哪个,都不影响最后的结果,所以BFS要找的就是最少的操作数,最后排个序就能达到题目要求了。
详情请见代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
bool flag[4][4][4][4][4][4][4][4][4];
int op[10][10] = {{0},{1,2,4,5},{1,2,3},{2,3,5,6},{1,4,7},{2,4,5,6,8},
{3,6,9},{4,5,7,8},{7,8,9},{5,6,8,9}};
int st[10];
struct node
{
int state[10];
int pos;//从起始状态到当前状态经过的操作数
int ans[200];//从起始状态到当前状态所有的操作
friend bool operator < (struct node a,struct node b)
{
return a.pos > b.pos;
}
}s,now;
void Bfs()
{
priority_queue<node> lcm;
int i,j;
memset(flag,0,sizeof(flag));
for(i = 1;i <= 9;i ++)
s.state[i] = st[i];
s.pos = 0;
flag[st[1]][st[2]][st[3]][st[4]][st[5]][st[6]][st[7]][st[8]][st[9]] = 1;
lcm.push(s);
while(!lcm.empty())
{
now = lcm.top();
lcm.pop();
for(i = 1;i <= 9;i ++)
{
s = now;
for(j = 0;op[i][j];j ++)
{
s.state[op[i][j]] ++;
if(s.state[op[i][j]] >= 4)
s.state[op[i][j]] -= 4;
// s.state[op[i][j]] %= 4;
}
if(!flag[s.state[1]][s.state[2]][s.state[3]][s.state[4]][s.state[5]][s.state[6]][s.state[7]][s.state[8]][s.state[9]])
{
s.ans[s.pos ++] = i;
flag[s.state[1]][s.state[2]][s.state[3]][s.state[4]][s.state[5]][s.state[6]][s.state[7]][s.state[8]][s.state[9]] = 1;
lcm.push(s);
}
if(!s.state[1] && !s.state[2] && !s.state[3] && !s.state[4] && !s.state[5]
&& !s.state[6] && !s.state[7] && !s.state[8] && !s.state[9])
{
// printf("%d",s.ans[0]);
sort(s.ans,s.ans + s.pos);//所有的操作互不干扰,无先后之分的
for(j = 0;j < s.pos;j ++)
printf("%d ",s.ans[j]);
printf("\n");
return;
}
}
}
}
int main()
{
int i,j;
while(scanf("%d",&j) != EOF)
{
st[1] = j;
for(i = 2;i <= 9;i ++)
{
scanf("%d",&st[i]);
}
Bfs();
}
return 0;
}
相关文章推荐
- vijosP1016 北京2008的挂钟
- vijosP1016北京2008的挂钟 BFS + 优先队列
- 北京2008奥运体育场馆展望
- C++中堆(优先队列)的应用:make_heap, pop_heap, push_heap, sort_heap, priority_queue
- 算法学习(六)--优先队列
- STL priority_queue 优先队列
- 优先队列
- STL 优先队列
- HDU 4198 Quick out of the Harbour (优先队列BFS)
- POJ3635-搜索,优先队列
- 堆、堆排序、优先队列
- 优先队列实现n路归并算法O(n * lgK)
- hdu 1236 排名(优先队列)
- POJ 1442 Black Box(优先队列)
- 堆排序与优先队列
- HDU4544 湫湫系列故事——消灭兔子(贪心+优先队列)
- HDU 1873 看病要排队 优先队列
- STL容器之优先队列
- poj2049Finding Nemo(优先队列+bfs)
- hdu 2850(贪心+优先队列)