码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 1166 The Clocks 位运算与BFS

时间:2017-04-02 22:54:10      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:break   memset   ios   输入   i++   ret   logs   pen   str   

1.题意:有一组3*3的只有时针的挂钟阵列,每个时钟只有0,3,6,9三种状态;对时针阵列有9种操作,每种操作只对特点的几个时钟拨一次针,即将时针顺时针波动90度,现在试求从初试状态到阵列全部指向0的状态所需要的最小操作数的操作方案;

2.输入输出:输入给出阵列初始状态,0,1,2,3分别表示0,3,6,9;要求输出最快方案的操作序列;

3.分析:IOI 1994的考题,BFS是比较容易想到的方法之一,关键是如何简洁的表示和改变BFS过程中的阵列状态;这里使用位运算的方法;具体如下:

首先一共9个时钟,每个时钟有0,1,2,3这4种状态,所以每个时钟可以由两位二进制数表示,则整个阵列就可以用18位二进制数表示,这里表示的问题就解决了;下一步就是如何表示"转动90度了",这里分三步,1)从状态中取出要调整的那个钟,2)对取出的sub部分进行模拟转动90度的操作,3)将处理完的sub放回原状态;经过这样的三个步骤之后,对一个钟的修改就完成了,针对每种操作,对这个操作内的每个时钟进行修改,就对当前状态完成了操作;

综上所述,这样的位运算方法使得表示更加简洁,计算的更快;具体代码如下:

 

 1 # include <cstdio>
 2 # include <iostream>
 3 # include <queue>
 4 # include <cstring>
 5 # include <stack>
 6 using namespace std;
 7 const int MAXN=1<<18;
 8 int clock[10];
 9 int vis[MAXN];
10 struct Node
11 {
12     int status,move,pre;
13     Node (){}
14     Node(int ss,int mm,int pp)
15     {
16         status=ss;
17         move=mm;
18         pre=pp;
19     }
20 }L[MAXN];
21 int M[9][5]=
22 {{0,1,3,4,-1},{0,1,2,-1,-1},{1,2,4,5,-1},
23  {0,3,6,-1,-1},{1,3,4,5,7},{2,5,8,-1,-1},
24  {3,4,6,7,-1},{6,7,8,-1,-1},{4,5,7,8,-1}};
25 void Init()
26 {
27     for(int i=0;i<9;i++)
28         scanf("%d",&clock[i]);
29     memset(vis,0,sizeof(vis));
30 }
31 void Solve()
32 {
33     queue<Node> Q;
34     int start=0;
35     int len=0;
36     for(int i=0;i<9;i++)
37         start|=(clock[i]<<(i<<1));
38     Q.push(Node(start,-1,-1));
39     vis[start]=1;
40     while(!Q.empty())
41     {
42         Node temp=Q.front();
43         Q.pop();
44         L[len++]=temp;
45         if(temp.status==0)
46             break;
47         //printf("%d\n",temp.move);
48         for(int i=0;i<9;i++)
49         {
50             int nclock=0;
51             int nstatus=temp.status;
52             for(int j=0;j<5;j++)
53                 if(M[i][j]>=0)
54                 {
55                     nstatus&= ((1<<18)-1) ^ (3<<(2*(M[i][j])));
56                     //"1111[目标位]1111",把待处理部分位的位置清零 
57                     nclock=(temp.status >> (2*(M[i][j]))) & 3;
58                     //取出要处理的部分位 
59                     nstatus|=((nclock+1) & 3) << (2*(M[i][j]));
60                     //填入处理后的部分位 
61                 }
62             if(!vis[nstatus])
63             {
64                 Q.push(Node(nstatus,i,len-1));
65                 vis[nstatus]=1;
66             }    
67         }    
68     }
69     len--;
70     stack<int> S;
71     while(1)
72     {
73         S.push(L[len].move+1);
74         len=L[len].pre;
75         if(L[len].pre<0)
76             break;
77     }
78     printf("%d",S.top());
79     S.pop();
80     while(!S.empty())
81     {
82         int t=S.top();
83         S.pop();
84         printf(" %d",t);
85     }
86     printf("\n");
87 }
88 int main()
89 {
90     //freopen("in.txt","r",stdin);
91     //freopen("out.txt","w",stdout);
92     Init();
93     Solve();
94     return 0;
95 }

 

POJ 1166 The Clocks 位运算与BFS

标签:break   memset   ios   输入   i++   ret   logs   pen   str   

原文地址:http://www.cnblogs.com/cnXuYang/p/6659520.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!