有9个时钟,排成一个3*3的矩阵。
|——-| |——-| |——-|
| | | | | | |
|—O | |—O | | O |
| | | | | |
|——-| |——-| |——-|
A B C
|——-| |——-| |——-|
| | | | | |
| O | | O | | O |
| | | | | | | | |
|——-| |——-| |——-|
D E F
|——-| |——-| |——-|
| | | | | |
| O | | O—| | O |
| | | | | | | |
|——-| |——-| |——-|
G H I
(图 1)
现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。
移动 影响的时钟
1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI
9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。
输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。
3 3 0
2 2 2
2 1 2
4 5 8 9
1166
#include
#include
#include
#include
using namespace std;
unsigned int clocks[10];
//保存最后最少的移动次数,最多也就是27次
int min_res = 28, tmp = 0;
//保存最小次数时候的移动方法
unsigned int min_op[10] = {0}, op[10] = {0};
void isOk(const unsigned int i1,const unsigned int i2,const unsigned int i3);//如果验证成功 那么返回1 否则返回0
void enumerate()//将前3行的拨钟数目进行枚举 返回枚举方法 循环写在这里面
{
for(unsigned int i=0;i<4;i++)
{
for(unsigned int j=0;j<4;j++)
{
for(unsigned int k=0;k<4;k++)
{
isOk(i,j,k);
}
}
}
}
/*
1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI
*/
void isOk(const unsigned int i1,const unsigned int i2 ,const unsigned int i3)//如果验证成功 那么返回1 否则返回0
{
op[1]=i1;
op[2]=i2;
op[3]=i3;
op[4]=(4-(clocks[1]+op[1]+op[2])%4)%4;//确定A
op[5]=(4-(clocks[2]+op[1]+op[2]+op[3])%4)%4;//确定B
op[6]=(4-(clocks[3]+op[2]+op[3])%4)%4; //确定C
op[7]=(4-(clocks[4]+op[1]+op[4]+op[5])%4)%4;//确定D
op[8]=(4-(clocks[7]+op[4]+op[7])%4)%4;//确定G
op[9]=(4-(clocks[5]+op[1]+op[3]+op[5]+op[7])%4)%4;//确定E
//f h i
if((clocks[6]+op[3]+op[5]+op[6]+op[9])%4==0 && (clocks[8]+op[5]+op[7]+op[8]+op[9])%4==0
&& (clocks[9]+op[6]+op[8]+op[9])%4==0)//满足条件
{
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 int)*10);
return ;
}
else//不符合要求 直接return继续寻找
{
return ;
}
}
return ;
}
int main()
{
int tag0=0;
for (int i = 1; i <= 9; i++)
cin >> clocks[i];
//非零项排序
enumerate();
vector<unsigned int> res;
for (int i = 1; i <= 9; i++)
{
if (min_op[i] != 0)
{
tag0=1;
res.push_back(i);
min_op[i]--;
i--;
}
}
sort(res.begin(), res.end());
if(tag0)
{
/**/
for (vector<unsigned int>::iterator it = res.begin(); it != res.end(); it++)
cout << *it << ' ';
}
else cout << "0";
cout <return 0;
}
/*这一题实质类似熄灯问题和画家问题。其共通点在于:
熄灯问题中,每个灯最多熄灯一次,因为灯只有两种状态,
并且循环。而这里,有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个组合,不会超时。
这题还可以列出一个方程组,九个未知数,通过高斯消元法来解方程组。*/
//思路引用于:http://www.cnblogs.com/CCBB/archive/2011/09/13/2175043.html