HDU 1584 蜘蛛牌(DFS,值得收藏)

Problem Description

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

Input

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

Output

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

Sample Input

1
1 2 3 4 5 6 7 8 9 10

Sample Output

9

题意:找到那个最小代价的移动距离。比如这一题的样例中,1移到2上面,花费1个代价,然后12就视为一体了,然后再把12移到3上面,又花费1个代价,直到最后将所有的牌全部移到10下面,就结束,得到了最小移动代价为9。如果还是不明白题意,其实可以玩一玩电脑里的蜘蛛纸牌。

这个题要好好收藏,网上都说是一道很简单的dfs题,但就我个人而言,并不觉得它很简单。初次看到这道题的时候,我也知道可能是要用dfs来搜,但不知道如何搜。因为我刚开始就想错了方向,一直在纠结如何用dfs来更新数组,如何来表示一个牌移动到另一张牌下面的这个行为。我当时感觉不可能用一个好的方式来表达牌的移动,所以我就不知道从何下手了。

在网上看到大牛们的思路后,终于明白了!具体操作是这样的:每次,我们理论上都可以选择9种牌来移动(大小1–9,10不能移动),每一张牌的移动到的位置有几种选择呢?有些人说,那还用问吗,肯定是只有一种啊,只能移动到大小比它大一的牌下面啊。好,这个地方那就和我一样想错了。

比如我们现在要移大小为5的这张牌,按照我们上面说的,直接移到6的位置下就可以了,其实是不对的。因为6这张牌它可能已经被移动过,如果6这张牌在我移动5之前被移动过,那么6肯定是移动到了7的下面,那我们就得把5移到大小为7的牌下!那如果7也被移动过,那么意味着7, 6都在8的下面,那么我们又得把5移到8的下面了!

那么我们如何表示牌的移动呢?其实用一个标记数组就行了,因为每一张牌必定只能移动到大小比它大一的牌之下,所以只要tag[i] = 1就表示i这张牌被移动过!

文字说明可能有点啰嗦,可能看代码还好理解一些,确实感觉一些东西只可意会

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;

const int INF = 1000000;
const int maxn = 11;
int a[maxn];						//记录大小为s的牌所在的位置				
int min_res = INF;
int tag[maxn];

void dfs(int k, int cost)
{
	if(cost > min_res)			//剪枝不能忘
		return ;
	if(k == 10)
	{
		if(cost < min_res)
			min_res = cost;
		return ;
	}
	for(int i = 1;i < 10;i++)		//理论上,每次可以选择9种大小的牌移动(不考虑有牌移动过) 
	{
		if(!tag[i])		//如果该大小的牌没有被移动 
		{
			//那么它只能移动到比它大1的牌下面
			//由于比它大1的牌可能已经移动到别的地方 
			for(int j = i + 1;j <= 10;j++)	 
			{
				if(!tag[j])
				{
					tag[i] = 1;
					dfs(k + 1, cost + abs(a[i] - a[j]));
					break;	//这里好好理解,找到一个就跳出,不用往后再找,其实理由理解了很简单 
				}
			}
			tag[i] = 0;	//这里回溯! 
		}
	}
}

int main()
{
	int t;
	cin >> t;
	while(t-- > 0)
	{
		memset(tag, 0, sizeof(0));
		min_res = INF;
		int s;
		for(int i = 1;i <= 10;i++)
		{
			cin >> s;				//输入牌的大小 
			a[s] = i;				//表示大小为s的牌放在数组第i位 
		}
		dfs(1, 0);
		cout << min_res << endl;
	}
	return 0;
}

本题最大的收获就是让我体会到dfs居然可以这样用,在遍历的同时,利用数组下标和参数,就能将结果算出。在无形之中就完成了我认为的不可能解决的问题。

其实题中的移动并不需要我们真的把数组中的元素移来移去,只需要在脑海中移动

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值