拨钟问题

题目:有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 



i)算法思路:因为操作1、2、3和操作4、5、6就能确定时钟A,B,C的状态,所以可以根据枚举操作1、2、3的组合来确定4、5、6操作如何进行,类似确定7、8、9操作的执行

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
void operate(int operations[10][10],int clock2[10],int opNum,int opCount)
{
 for(int i = 1;i <= 9;i ++)
 {
  clock2[i] += operations[opNum][i]*opCount;
  clock2[i] %= 4;
 }
}
int main()
{
 int clock[10];
 int clock2[10];
 int minTimes = 28;
 int opTimes[10];
 int minOpTimes[10];
 int operations[10][10] =
 {
  {0},
  {0,1,1,0,1,1,0,0,0,0},
  {0,1,1,1,0,0,0,0,0,0},
  {0,0,1,1,0,1,1,0,0,0},
  {0,1,0,0,1,0,0,1,0,0},
  {0,0,1,0,1,1,1,0,1,0},
  {0,0,0,1,0,0,1,0,0,1},
  {0,0,0,0,1,1,0,1,1,0},
  {0,0,0,0,0,0,0,1,1,1},
  {0,0,0,0,0,1,1,0,1,1},
 };
 //保存1,2,3的操作的所有组合方式
 int move123[64][3];//每种操作有0,1,2,3共4种选择,所以共有4^3中组合方式
 for(int i = 0;i < 64;i ++)
 {
  int num = i;
  for(int j = 2;j >= 0;j --)  //把num换成4进制数
  {
   move123[i][j] = num % 4;
   num /= 4;
  }           
 }
 
 for(int x = 1;x <= 9;x ++)
 cin >> clock[x];
 for(int i = 0;i < 64;i ++)
 {
  memcpy(clock2,clock,sizeof(int) * 10);
  memset(opTimes,0,sizeof(int) * 10);
  
  for(int j = 1;j <= 3;j ++)
  {
   opTimes[j] = move123[i][3-j];  //跟前面求1,2,3所有的操作呼应 ,使执行的次数从小到大枚举
   operate(operations,clock2,j,opTimes[j]);
  }
  for(int j = 4;j <= 6;j ++)
  {
   opTimes[j] = (4 - clock2[j-3]) % 4;
   operate(operations,clock2,j,opTimes[j]);
  }
  opTimes[7] = (4 - clock2[4]) % 4;
  operate(operations,clock2,7,opTimes[7]);
  opTimes[9] = (4 - clock2[6]) % 4;
  operate(operations,clock2,9,opTimes[9]);
  
  if(clock2[5] == 0 && clock2[7] == clock2[8] && clock2[8] == clock2[9])   //判断E是否为零,还有最后三是否相等
  {
   opTimes[8] = (4 - clock2[7]) % 4;
   int tem = 0;
   for(int i = 1;i <= 9;i ++)
   tem += opTimes[i];
   if(tem < minTimes)
   {
    minTimes = tem;
    memcpy(minOpTimes,opTimes,sizeof(int) * 10);
   }
  }
 }
 
 vector <int> result;
 for(int i = 1;i <= 9;i ++)
 {
  while(minOpTimes[i] --)
  {
   result.push_back(i);
  }
 }
 sort(result.begin(),result.end());
 vector<int>::iterator it;
 for(it = result.begin();it != result.end();it ++)
 cout << *it <<' ';
 cout << endl;
 return 0;
}

ii)很遗憾没能看懂

#define TABLE_LEN 5
#include<stdio.h>
const int table[10][TABLE_LEN]=
    {{},{1,2,4,5},{1,2,3},{2,3,5,6},
        {1,4,7},{2,4,5,6,8},{3,6,9},
        {4,5,7,8},{7,8,9},{5,6,8,9}};
int state[10];
int times[10],min=0x7FFFFFFF,ans_times[10];
bool isFirst=true;
void deal(int k,int total)
{
    if (k==10)
    {
        for (int i=1;i<=9;i++)
            if (state[i]&3)
                return;
        if (total<min)
        {
            min=total;
            for (int i=1;i<=9;i++)
                ans_times[i]=times[i];
        }
        return;
    }
    for (times[k]=0;times[k]<4;times[k]++)  //每个操作最多执行3次
    {
        for (int i=0;i<TABLE_LEN;i++)
            state[table[k][i]]+=times[k];
        deal(k+1,total+times[k]);
        for (int i=0;i<TABLE_LEN;i++)
            state[table[k][i]]-=times[k];
    }
    return;
}
int main()
{
    for (int i=1;i<=9;i++)
        scanf("%d",&state[i]);
    deal(1,0);
    for (int i=1;i<=9;i++)
        for (int j=0;j<ans_times[i];j++)
        {
            if (isFirst)
                isFirst=false;
            else
                printf(" ");
            printf("%d",i);
        }
    printf("\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值