zoukankan      html  css  js  c++  java
  • POJ 1166 The Clocks [BFS] [位运算]

    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
    ",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("
    ");
    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 }

     eg.位运算举例

    1.两位二进制数表示一个状态,4个一组,即8位二进制数表示一组状态

    2.要实现的操作,对第i+1个状态进行加一操作

    3.大体思路:1)待处理状态num做一个副本n; 2)num把要处理掉的那一位挖空 ;3)把待处理单位sub从n取出;

                     4)对sub操作 ;5)把sub塞回去

     1 void Init()
     2 {
     3     int num=0;
     4     for(int i=0;i<4;i++)
     5         num|=(Num[i]<<(i*2));
     6 }
     7 void Change(int i)
     8 {
     9     int n=num;
    10     num&=((1<<8)-1)^(3<<(i*2));
    11     //把要处理的那一位挖空为什么是3呢,因为二进制"11"为3,正好把两个二进制位"挖空"
    12     int sub=(n>>(i*2))&3;//这样除了最低的两位其他的都会与0做&运算,都扑街了
    13     sub+=1;
    14     num|=(sub<<(2*i));
    15 } 
  • 相关阅读:
    ThinkPHP框架返回插入记录的id号
    TP框架中关于if、else 分支结构逻辑错误
    SVN 快速入门!
    TP框架中如何使用SESSION限制登录?
    TP框架M方法 create方法丢失字段问题
    .NET Framework 工具
    X86-64寄存器和栈帧
    微软开源资源 NET Foundation Projects
    Import 元素 (MSBuild)
    C#开源资源项目
  • 原文地址:https://www.cnblogs.com/cnXuYang/p/6659520.html
Copyright © 2011-2022 走看看