正文

第17次编程比赛第2题解法2006-02-25 18:10:00

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

分享到:

/* 现有3×3的九个方格,空出中心的方格,将数字1-8随机的放入到其它的8个方格中,数字1不动,其它的数字可以移动,   最终,使所有数字按1-8的顺序顺时针排列外围方格中。移动的规则是:   都可以移向横排或竖排相临空着的方格,而且,都可以移向中心空着的方格。   要求计算出移动移动最少的次数。        函数接口: int minMove(int a[]);    其中 a[] 表示从左上角顺时针放入的8个数。*//*2006-2-25*/ /*算法介绍: 1。设定位置标号:从左上角按顺时针依次设定位置标号为1-8,中间的空格位置标号为0。*2。创建一个类,其对象为数字1-8。为每个对象的属性包括位置标号pos和数字大小num。*3。定义一个对象数组,数组元素依次为数字1-8。为方便起见,这里使每个元素的大小等于其下标值。*4。从数字2开始依次按照移动规则操作每个数字,使其按顺序顺时针排列到外围方格中。    操作方法:若数字n(2 <= n <=8 )已经位于n-1之后,则对n不做任何操作,直接操作n+1;    若数字n不在n-1之后,则:    1。若n处于中间的方格中(指位置标号为2,4,6,8处,非中间空格处),则将其移至中间空格处,然后将其位置前面的数字依次按逆时针移动,直到空出一个合适的方格,即方格的前一位置处是数字n-1,将n移到该空方格处。    2。若n不处于中间的方格中(即位置标号为1,3,5,7处),则将其移到中间的方格中。    具体操作为:将n位置前面的数字移至中间空格处,然后将它及其位置后面的数字依次按逆时针移动,直到空出一个合适的方格,即方格的后一位置处的数字比n大或者是数字1,将中间空格处的数字移到该空方格处。此时n已经处于中间的方格中。    *5。累计每次移动,最后返回移动的次数,此即移动最少的次数。*6。本程序还可以打印每次移动后各数字的分布情况(中间空格处无数字),    用户可以将其打印出来以便帮助实际操作。 */ #include using namespace std;int count = 0;   //全局变量,用来累计移动的次数 const int Max = 8; //全局变量,表示数的个数 class Date{   //创建一个类,用来描述每一个数字的大小和位置标号    int pos;    int num;public:    int GetPos()  //读取位置标号     {        return pos;    }    int GetNum()//读取数字大小     {        return num;    }    void SetPos(int p) //设置位置标号     {        pos = p;    }    void SetNum(int n) //设置数字大小     {                      num = n;    }    int PrePos() //读取该数字的前一位置标号     {        if (pos == 1)            return 8;        else            return pos-1;    }        Date operator =(Date A)    {        pos = A.GetPos();        num = A.GetNum();                return *this;    }};void SetDate(const int a[], Date A[]);//根据传入的数据,设置对象数组 void PrintDate(const Date A[]);//打印对象数组,即各数字的分布情况(中间空格处无数字)void SortDate(Date A[]); //按照位置标号大小,用选择排序法对数组元素进行排序 int NextPos(int pos); //传入一个位置标号,返回该位置之后的位置标号 void MoveDate(Date A[], int blank, int n); //按要求移动数字 bool IsMid(int pos);//传入一个位置标号,判断该位置是否处于中间 void ToMid(Date A[], Date D); //将数字对象D移到外围方格中间的方格中int ToCen(Date &D); //将数字对象D移到中间的空格格中int Forward(Date &D);//传入一个数字对象,将其按逆时针顺序向前移动int MinMove(int a[]); //计算出移动移动最少的次数int main()             {    int a[Max] = {1, 2, 3, 4, 5, 6, 8, 7};    cout << "c=" << MinMove(a) << "\n";            getchar();    return 0;}int MinMove(int a[]){    Date A[Max+1];    int blank;    extern int count;        SetDate(a, A); //根据传入的数据,设置对象数组         PrintDate(A); //打印对象数组,即各数字的分布情况(中间空格处无数字)       for (int i=2; i<=Max; i++) //从数字2开始依次按照移动规则操作每个数字    {            if (A[i].PrePos() != A[i-1].GetPos()) //若数字i未按顺序排列         {                    if (! IsMid(A[i].GetPos())) //若数字i不处于中间的方格中                 ToMid(A, A[i]);  //则将其移到中间的方格中                        //    cout << "c=" << count << "\n";             //    PrintDate(A);                     //若数字i已经按顺序排列了,跳过后面的操作,操作数字i+1             if (A[i].PrePos() == A[i-1].GetPos())            {                //    cout << "c=" << count << "\n";            //    PrintDate(A);                   continue;            }                        // 否则,把数字i移到中间空格处,并将其位置前面的数字依次按逆时针移动             //直到空出一个合适的方格,即方格的前一位置处是数字i-1,将i移到该空方格处。            blank = ToCen(A[i]);            MoveDate(A, blank, i);                     //    cout << "c=" << count << "\n";          //    PrintDate(A);         }    }       // PrintDate(A);       return count;}/*函数介绍: 传入一个位置标号,返回该位置之后的位置标号 */int NextPos(int pos){    if (pos == 8)        return 1;    else        return pos + 1;}/*函数介绍: 若n处于中间的方格中(指位置标号为2,4,6,8处,非中间空格处),则将其移至中间空格处,然后将其位置前面的数字依次按逆时针移动,直到空出一个合适的方格,即方格的前一位置处是数字n-1,将n移到该空方格处。 *形参: Date A[]:对象数组     int blank:空格处的位置标号    int n:正在处理的数字对象的下标,即其数字的大小 */void MoveDate(Date A[], int blank, int n){    extern int count;        while (1)    {        for (int i=1; i<=Max; i++) //将n的位置前面的数字依次按逆时针移动        {            if (A[i].PrePos() == blank)            {                blank = Forward(A[i]);                    count++;                break;            }        }                //如果空格在中间,并且空格之前的数字为n-1,则停止移动其他数字         if ((IsMid(blank)) && (blank == NextPos(A[n-1].GetPos())))            break;    }        A[n].SetPos(blank);  //将n移到空方格处    count++;        }/*函数介绍: 传入一个位置标号,判断该位置是否处于中间 */bool IsMid(int pos){    if (pos == 2 ||   pos == 4 || pos == 6 || pos == 8)        return true;    else        return false;}/*函数介绍: 若n不处于中间的方格中(即位置标号为1,3,5,7处),则将其移到中间的方格中。    具体操作为:将n位置前面的数字移至中间空格处,然后将它及其位置后面的数字依次按逆时针移动,直到空出一个合适的方格,即方格的后一位置处的数字比n大或者是数字1,将中间空格处的数字移到该空方格处。此时n已经处于中间的方格中。*形参: Date A[]:对象数组     Date D:正在处理的数字对象 */void ToMid(Date A[], Date D){    extern int count;    int flag = 0;         int blank;        for (int i=1; i<=Max; i++)  //将n位置前面的数字移至中间空格处    {        if (A[i].GetPos() == D.PrePos())        {                 blank = ToCen(A[i]);            break;        }    }               while (1)    {            for (int i=1; i<=Max; i++) //将它及其位置后面的数字依次按逆时针移动        {            if (A[i].PrePos() == blank)            {                     blank = Forward(A[i]);                count++;                      break;            }        }                if (IsMid(blank))//直到发现一个合适的空格         {               for (int i=1; i<=Max; i++)            {                if ((A[i].GetPos() == NextPos(blank)) &&                 ((A[i].GetNum() > D.GetNum()) || (A[i].GetNum() == 1)))                {                      flag = 1;                    break;                }            }        }                if (flag == 1)            break;    }        for (int i=1; i<=Max; i++) // 将中间空格处的数字n移到该空方格处    {        if (A[i].GetPos() == 0)        {               A[i].SetPos(blank);            count++;               break;        }    }    }/*函数介绍: 传入一个数字对象,将其移到中间空格(位置标号为0)处 */int ToCen(Date &D){    extern int count;    int blank = D.GetPos();        D.SetPos(0);    count++;            return blank;}/*函数介绍: 传入一个数字对象,将其按逆时针顺序向前移动*/int Forward(Date &D){    int blank = D.GetPos();        D.SetPos(D.PrePos());        return blank;}/*函数介绍: 根据传入的数据,设置对象数组 */void SetDate(const int a[], Date A[]){    for (int i=0; i

阅读(4861) | 评论(0)


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

评论

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