zoukankan      html  css  js  c++  java
  • POJ 1166 The Clocks

    http://poj.org/problem?id=1166

    很多人都用的暴力穷举的方法,也即搜索空间为:4^9=262144。

    我只枚举了前三个,也即4^3=64种情况,后6种就可以直接算出来了。


    /********************************************************************************************************
    2814:拨钟问题

    http://poj.grids.cn/practice/2814

    时间限制:
    1000ms
    内存限制:
    65536kB

    描述
    有9个时钟,排成一个3*3的矩阵。

    现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如右表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。

    移动 影响的时钟
    1 ABDE
    2 ABC
    3 BCEF
    4 ADG
    5 BDEFH
    6 CFI
    7 DEGH
    8 GHI
    9 EFHI
    (图 2)
    输入
    从标准输入设备读入9个整数,表示各时钟指针的起始位置。0=12点、1=3点、2=6点、3=9点。
    输出
    输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号大小,输出结果。
    样例输入

    3 3 0 
    2 2 2 
    2 1 2 

    样例输出

    4 5 8 9 
    *******************************************************************************************************
    */

    /********************************************************************************************************
    解题思路:

    假设时钟指针位置对应的值为clock_time,那么顺时针旋转90°就是clock_time = (clock_time+1)%4
    这一组时针就用一个数组表示。9种操作对应一个二维数组。

    这一题实质类似熄灯问题和画家问题。其共通点在于:
    操作对环境的改变是无序的,每个操作都会影响到周围的状态。
    同时每一种操作都有周期性限制,也即最多需要几次操作,多于这个次数产生循环。

    熄灯问题中,每个灯最多熄灯一次,因为灯只有两种状态,
    并且循环。而这里,有4种循环的状态,因此每个移动操作顶多使用3次。

    我们对移动方法1,2,3进行枚举,每种方法无非实施0-3次,也即一共4^3=64种情况。
    这些情况之间并非没有关系。

    例如,我们确定了1,2,3的情况数,那么得到一个灯A,B,C的状态,而只有移动4能够改变A,
    移动5能够改变B,移动6能够改变C,那么移动4-6的次数也确定了。

    同样,这时只有移动7能够改变D,移动9能够改变F,这时移动7和9的次数也确定了。

    最后,时钟A,B,C,D,F都已经到达12点,E,G,H,I还没确定,只剩下移动8能够改变GHI,
    所以只要检查E是否已经到达12点以及,GHI的时钟数是否相等就行了。

    最后找到一个移动次数最小的情况。

    这题也可以用暴力搜索,因为最多有4^9个组合,不会超时。

    这题还可以列出一个方程组,九个未知数,通过高斯消元法来解方程组。
    *******************************************************************************************************
    */

    #include 
    <iostream>
    #include 
    <cmath>
    #include 
    <cctype>
    #include 
    <string>
    #include 
    <map>
    #include 
    <set>
    #include 
    <vector>
    #include 
    <algorithm>
    #include 
    <list>
    #include 
    <stack>
    #include 
    <cstring>
    //#include <stdlib.h>
    //#include <iomanip>

    using namespace std;

    void operate(unsigned operations[10][10], unsigned clocks2[10], int op_num, int op_count)
    {
        
    for (int i = 1; i <= 9; i++)
        {
            clocks2[i] 
    += operations[op_num][i]*op_count;
            clocks2[i] 
    %= 4;
        }
    }

    int main()
    {
        
    //保存原始的时钟状态
        unsigned clocks[10= {0};

        
    //保存最后最少的移动次数,最多也就是27次
        int min_res = 28, tmp = 0;
        
    //保存最小次数时候的移动方法
        unsigned min_op[10= {0};

        
    //9种操作对应数组
        unsigned operations[10][10= 
        {
            {
    0},
            
    // A  B  C D  E F  G  H  I
            {0110110000},  //op1: ABDE
            {0111000000},  //op2: ABC
            {0011011000},  //op3: BCEF
            {0100100100},  //op4: ADG
            {0010111010},  //op5: BDEFH
            {0001001001},  //op6: CFI
            {0000110110},  //op7: DEGH
            {0000000111},  //op8: GHI
            {0000011011}  //op9: EFHI
        };

        
    //移动操作改变数据clocks2,而clocks备份源数据
        unsigned clocks2[10= {0};

        
    //记录每种移动方法操作次数
        unsigned op[10= {0};
        
        
    //保存枚举移动1,2,3的64种执行情况
        unsigned move123[64][3];

        unsigned num, divide_num;
        
    for (int i = 0; i < 64; i++)
        {
            num 
    = i;
            
            
    //将10进制i转换为对应的4进制move123[i]
            for (int j = 2; j >= 0; j--)
            {
                divide_num 
    = (unsigned)num/4;
                move123[i][j] 
    = num - divide_num*4;
                num 
    = divide_num;
            }
        }

        
    for (int i = 1; i <= 9; i++)
            cin 
    >> clocks[i];

        
    //枚举移动1,2,3的64种执行次数,计算出移动4-9的移动次数,判断是否满足最后条件,记录总次数
        for (int i = 0; i < 64; i++)
        {
            memcpy(clocks2, clocks, 
    sizeof(unsigned)*10);
            memset(op, 
    0sizeof(unsigned)*10);

            
    for (int j = 1; j <=3; j++)
            {
                op[j] 
    = move123[i][3-j];
                operate(operations, clocks2, j, op[j]);
            }

            
    //移动操作4,5,6的次数分别由时钟A,B,C的状态决定
            for (int j = 4; j <=6; j++)
            {
                op[j] 
    = (4-clocks2[j-3])%4;
                operate(operations, clocks2, j, op[j]);
            }

            
    //移动操作7,9的次数分别由时钟D,F的状态决定
            op[7= (4-clocks2[4])%4;
            operate(operations, clocks2, 
    7, op[7]);
            op[
    9= (4-clocks2[6])%4;
            operate(operations, clocks2, 
    9, op[9]);

            
    //判断E是否为0,GHI是否相等
            if (clocks2[5== 0 && clocks2[7== clocks2[8&& clocks2[8== clocks2[9])
            {
                op[
    8= (4-clocks2[7])%4;
                tmp 
    = 0;
                
    for (int j = 1; j <= 9; j++)
                    tmp 
    += op[j];
                
    if (tmp < min_res)
                {
                    min_res 
    = tmp;
                    memcpy(min_op, op, 
    sizeof(unsigned)*10);
                }
            }
        }

        
    //非零项排序
        vector<unsigned> res;
        
    for (int i = 1; i <= 9; i++)
        {
            
    if (min_op[i] != 0)
            {
                res.push_back(i);
                min_op[i]
    --;
                i
    --;
            }
        }

        sort(res.begin(), res.end());

        
    for (vector<unsigned>::iterator it = res.begin(); it != res.end(); it++)
                cout 
    << *it << ' ';

        cout 
    << "\n";

        
    return 0;
    }
  • 相关阅读:
    Python 中lambda 简单介绍
    关于python中带下划线的变量和函数 的意义
    Python 类的方法,下划线有什么不同?
    Python中用format函数格式化字符串的用法(2.7版本讲解哦!)
    如何理解 Python 中的__init__
    Python引用多个模块,调用模块中的函数时,要注意的地方
    Python tips: 什么是*args和**kwargs?
    如何简单地理解Python中的if __name__ == '__main__'
    NLP点滴——文本相似度
    马里奥AI实现方式探索 ——神经网络+增强学习
  • 原文地址:https://www.cnblogs.com/CCBB/p/2175043.html
Copyright © 2011-2022 走看看