博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 1166 - The Clocks
阅读量:6878 次
发布时间:2019-06-26

本文共 4433 字,大约阅读时间需要 14 分钟。

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
        {
0
1
1
0
1
1
0
0
0
0
},  
//
op1: ABDE
        {
0
1
1
1
0
0
0
0
0
0
},  
//
op2: ABC
        {
0
0
1
1
0
1
1
0
0
0
},  
//
op3: BCEF
        {
0
1
0
0
1
0
0
1
0
0
},  
//
op4: ADG
        {
0
0
1
0
1
1
1
0
1
0
},  
//
op5: BDEFH
        {
0
0
0
1
0
0
1
0
0
1
},  
//
op6: CFI
        {
0
0
0
0
1
1
0
1
1
0
},  
//
op7: DEGH
        {
0
0
0
0
0
0
0
1
1
1
},  
//
op8: GHI
        {
0
0
0
0
0
1
1
0
1
1
}  
//
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, 
0
sizeof
(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
;
}

转载于:https://www.cnblogs.com/CCBB/archive/2011/09/13/2175043.html

你可能感兴趣的文章
【Linux系统安装】磁盘与分区的命名规则
查看>>
运维经验分享(七)-- Linux Shell之ChatterServer服务控制脚本第三次优化
查看>>
自定义nginx版本号
查看>>
感悟:周末实施
查看>>
Shell流程控制
查看>>
请在服务器管理器的 Tomcat 定制器中设置 manager-script 角色的正确用户名和口令。...
查看>>
SCCM TP4部署UWP应用之证书分发
查看>>
shell脚本工具之条件测试
查看>>
mysql 锁机制
查看>>
mongodb 3.0 配置
查看>>
2012年收获中带着无限感谢
查看>>
SANBoot安装系统
查看>>
《跟老男孩学Linux运维:核心基础实战》勘误与反馈
查看>>
【中级】华为设备VRRP双机双组热备配置实战
查看>>
实现JSP页面
查看>>
【iOS-cocos2d-X 游戏开发之十】自定义各类模版&触屏事件讲解!
查看>>
SCN浅析
查看>>
吐槽“云计算”
查看>>
使用Cocos2d-x-3.0游戏引擎编写一个塔防游戏1
查看>>
Exchange 2010和Exchange 2016共存部署-4:Exchange2016部署先决条件
查看>>