【HDU-1584】蜘蛛牌

236 阅读2分钟
题目

蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起移动,游戏的目的是将所有的牌按同一花色从小到大排好,为了简单起见,我们的游戏只有同一花色的10张牌,从A到10,且随机的在一行上展开,编号从1到10,把第i号上的牌移到第j号牌上,移动距离为abs(i-j),现在你要做的是求出完成游戏的最小移动距离。

输入

第一个输入数据是T,表示数据的组数。 每组数据有一行,10个输入数据,数据的范围是[1,10],分别表示A到10,我们保证每组数据都是合法的。

输出

对应每组数据输出最小移动距离。

 

样例
Sample Input
1
1 2 3 4 5 6 7 8 9 10
 

Sample Output
9

 



 

AC代码
#include <iostream>
#include <cmath>
#include <string.h>

using namespace std;
int t,step,min_distance;
int a[11];
int visit[11];
void dfs(int distance)
{
    //不论10张牌怎样排列,最多都只需要移动9次(为什么不==10呢??以为10是不需要移动的),只是移动距离不确定.要使移动9次后移动的距离最小.
    if(step==9)
    {
        //移动完9次后,判断以下移动距离是否创新低,如果创新低,则更新.搜索成功,return开始下一次搜索
        if(distance<min_distance)
            min_distance=distance;
        return;
    }

    //如果还没有移动玩9次后就已经比已有的最低的记录大了,则剪纸,停止此次搜索。搜索失败,return开始下一次搜索
    if(distance>=min_distance)
        return;

    //从第一个数开始遍历
    for(int i=1;i<=9;i++)
    {
        //访问标志代表是否被移走。如果该牌没有被移动,则从此牌开始搜索,寻找与当前牌能组合的下一张牌
        if(visit[i]==0)
        {
            //因为要移走当前牌向后搜索了,所以移动次数加1,并设置标记,表示当前牌已被移走
            step++;
            visit[i]=1;
            //向后搜索,每一寻找后面的第一个没有被移走的牌
            for(int j=i+1;j<=10;j++)
            {
                if(visit[j]==0)//这里的效果确实是移动到比他大1的位置上去了,没有随便的乱移。比如要移1了,如果2,3,4,5都已经被移动过了 那么这几张牌必定叠放在6的下面,所以要移到6的位置
                {
                    //当前距离加上要移动的距离作为参数.注意:这里要移动的距离为“abs(a[i]-a[j])”,不是“abs(i-j)”.j表示要移动到的位置,这个位置不一定在i的右面,因为移动的是a[i],不是i
                                                            //i和j使相邻的,但这两点代表的两张牌的大小不一定相邻。而abs中的两个数代表此次跳转的起点和终点,这两点的牌的大小时要求是相邻的。
                                                            //由于在输入是做了处理,导致a[i]和a[j]在位置上不相邻,但这两点代表的牌的大小是相邻的,故可以把a[i]和a[j]当作跳转的起点和终点放在abs里
                                                            //a[i]代表牌值为i的牌所在的位置,a[j]代表牌值为j的牌所在的位置,又因为i和j的值是相邻的,故a[i]和a[j]的牌值是相邻的
                    dfs(distance+abs(a[i]-a[j]));
                    break;   //这个因为一旦找到下一个移动好的就跳出这个循环,因为你已经找到啦一个,就不用找下一个啦。如果回溯了 就像是又一个全排列 而且牌得移动不合理,比如2移到6了,结果回溯就直接跳过3~6到了7的下面
                }
            }
            //回溯
            visit[i]=0;
            step--;
        }
    }
}
int main()
{
    cin>>t;
    while(t--)
    {
        //每次都更新一些变量
        step=0;
        min_distance=0x3f3f3f3f;
        memset(visit, 0, sizeof(visit));
        for(int i=1;i<=10;i++)
        {
            //使得牌值为x的牌在第i位
            int x;
            cin>>x;
            a[x]=i;   
        }
        dfs(0);  //这里的0代表距离,刚开始时为0,不适合用1
        cout<<min_distance<<endl;
    }
    return 0;
}

 

题源:acm.hdu.edu.cn/showproblem…