正文

我的第15次编程比赛第2题程序2006-02-13 10:02:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/goal00001111/10070.html

分享到:

/*有十个开关等间距排成一线,每个开关对应其上方的一盏灯(十盏灯也排成一线)。每按动一下开关,可以使对应的灯改变状态(原来亮着的将熄灭,原来熄灭的将被点亮)。但是,由于开关之间的距离很小,每次按动开关时,相邻的一个开关也将被按动。例如:按动第5个开关,则实际上第4、5、6个开关都被按动。而按动靠边的第1个开关时,第1、2个开关都被按动。并且,无法只按动最靠边的一个开关。现在给出十盏灯的初始的状态和目标状态,要求计算:从初始状态改变到目标状态所需要的最少操作次数。函数接口:int MinChange(const int Start[],const int End[]);其中:Start表示了初始状态,End表示了目标状态。表示状态的数组(Start和End)中,若某元素为0表示对应的灯亮着,否则表示对应的灯没有亮。调用函数时保证Start和End数组长度均为10,并保证有解。*操作方法:设当前灯编号为i,其下一盏灯编号为i+1若i灯的初始状态与末状态相同,且i+1灯的初始状态与末状态相同:i = i + 1,不按开关;若i灯的初始状态与末状态相同,但i+1灯的初始状态与末状态不同:i = i + 2,按下开关;若i灯的初始状态与末状态不同,不论i+1灯的初始状态与末状态是否相同:i = i + 1,按下开关。若出现无解的情况,则操作次数取32768; 从左边和右边各顺序操作一次,取操作数较小的返回 *注:因为按照如上的操作方法,最边上的两个开关是不用亲自去按的;而这样会漏掉一些解。所以把初始状态扩展到4种情况:1。与给定的初始状态一模一样2。在原状态下,先按下最左边的开关 3。在原状态下,先按下最右边的开关4。在原状态下,先按下最左边和最右边的开关*//*2006-2-12 梁见斌*/ #include <iostream>#include <cmath> using namespace std; int MinChange(const int Start[],const int End[]);//把初始状态扩展到四种情况 void Change(int array[], int lable, int max);//按下开关,改变对应的灯及其相邻的灯的状态 int DMinChange(const int start[], const int end[]);//按照给定操作方法操作 int main(){ int a[10]={1,1,1,1,1};    int b[10]={1,0,0,0,0}; int n = 9;  n = MinChange(a, b); cout << "n=" << n << "\n";;  getchar(); return 0;} int MinChange(const int start[], const int end[]){ const int MAXLEN = 5;//存储灯的数量  int c_start[MAXLEN]; //存储灯的初始状态  int count;  //记录每一种初始状态下的最少操作数  int minCount;  //记录总的最少操作数  //从左边开始操作  for (int j=0; j<MAXLEN; j++) //复制数组   c_start[j] = start[j];  cout << "先不按任何开关,直接按照操作方法进行 \n"; minCount = DMinChange(c_start, end); //先不按任何开关,直接按照操作方法进行   cout << "先按下最左边的开关\n"; Change(c_start, 0, MAXLEN - 1);//先按下最左边的开关 count = DMinChange(c_start, end) + 1; //加上按最边上开关的操作  minCount = (minCount < count) ? minCount : count;  cout << "先按下最左边和最右边的开关\n"; Change(c_start, MAXLEN-1, MAXLEN - 1);//先按下最左边和最右边的开关 count = DMinChange(c_start, end) + 2; //加上按最边上开关的操作  minCount = (minCount < count) ? minCount : count;  cout << "先按下最右边的开关\n"; Change(c_start, 0, MAXLEN - 1);//先按下最右边的开关 count = DMinChange(c_start, end) + 1; //加上按最边上开关的操作  minCount = (minCount < count) ? minCount : count;  return minCount;}/*函数介绍:根据给定的初状态和末状态,按照操作方法顺序操作,返回所需的最少操作数  */int DMinChange(const int start[], const int end[]){ const int MAXLEN = 5;//存储灯的数量  int c_start[MAXLEN]; //存储灯的初始状态  int countLeft = 0;//累计从左边开始操作的所需的操作次数  int countRight = 0;//累计从右边开始操作的所需的操作次数  int i;  //从左边开始操作  for (int j=0; j<MAXLEN; j++) //复制数组   c_start[j] = start[j];  i = 0; while (i < MAXLEN - 1) {  if (c_start[i] == end[i])//若当前灯的初始状态与末状态相同   {   if (c_start[i+1] == end[i+1])//若相邻的下一盏灯的初始状态与末状态相同     i++;   else   {    if (i <= MAXLEN - 3)     {     i += 2;     Change(c_start, i, MAXLEN - 1);//按下开关,改变对应的灯及其相邻的灯的状态      cout << i;     //显示操作的步骤      countLeft ++;    }    else    {     countLeft = 32768;//出现错误的操作或无解      break;    }    }                     }  else  //若当前灯的初始状态与末状态不相同   {   i++;   Change(c_start, i, MAXLEN - 1);//按下开关,改变对应的灯及其相邻的灯的状态    cout << i;       //显示操作的步骤    countLeft ++;   }  } cout << "\n"; //从右边开始操作 for (int j=0; j<MAXLEN; j++) //复制数组   c_start[j] = start[j];   i = MAXLEN - 1;  while (i > 0) {  if (c_start[i] == end[i])  {   if (c_start[i-1] == end[i-1])    i--;   else   {    if (i >= 2)    {     i -= 2;     Change(c_start, i, MAXLEN - 1);//按下开关,改变对应的灯及其相邻的灯的状态      cout << i;   //显示操作的步骤      countRight++;    }    else    {     countRight = 32768;//出现错误的操作或无解      break;    }    }  }  else  {   i--;   Change(c_start, i, MAXLEN - 1);//按下开关,改变对应的灯及其相邻的灯的状态    cout << i;      //显示操作的步骤    countRight++;   }  } cout << "\n"; cout << "a=" << countLeft << "\n";   cout  << "b=" <<  countRight << "\n";  return (countLeft < countRight) ? countLeft : countRight;  } /*函数介绍:输入一个整型数组和某元素下标,以及数组长度,改变该元素极其相邻元素的状态(0或非0)  */void Change(int array[], int lable, int max){ if (lable > 0)  array[lable-1] = (array[lable-1] ? 0 : 1);   array[lable] = (array[lable] ? 0 : 1);  if (lable < max)  array[lable+1] = (array[lable+1] ? 0 : 1);}

阅读(4013) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册