这道题,让我把dfs突然搞不懂了,让我很糊涂。只知道每一次都回溯。
题目:
蜘蛛牌是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
题目大意:
蜘蛛纸牌大家都玩过,就是看怎么移动纸牌,最后的到的移动步数最小
算法:
dfs (剪枝)
代码:
#include<iostream>
#include<cmath>
using namespace std;
int a[15],b[15],ans; //数组a用来存储牌的位置,数组b作为标记数组
void dfs(int num,int sum)
{
int i,j;
if(sum>ans)//如果此时移动距离已经大于已经得到的最短距离,就返回
return;
if(num==9)//如果移动九次都没有大于已经得到的最短距离,就更新最短距离
{
ans=sum;
return; //回溯
}
for(i=1;i<=10;i++)
{
if(!b[i])//如果i还没有放入,给它找位置
{
b[i]=1; //标记已经移动
for(j=i+1;j<=10;j++) //j=i+1 因为i要放到比他大的牌的下边
if(!b[j]) //例如现在移动牌3,发现b[4]、b[5]都是1(4和5已经移动过了),也就是说4,5已经放到了6的下边
//所以将3放到6的下边
{
dfs(num+1,sum+abs(a[i]-a[j]));
break;
}
b[i]=0;//回溯
}
}
}
int main()
{
int n,i,j;
cin>>n;
while(n--)
{
for(i=1;i<=10;i++)
{
cin>>j;
a[j]=i;//牌号为j的扑克的位置是i
}
ans=100000000;
dfs(0,0);
cout<<ans<<endl;
}
return 0;
}
解析:
一定要注意 a[j]=i 表示 牌号为j的扑克的位置是i 。
采用dfs 每次都枚举十张牌,看他可以放到哪一个位置上。
例如现在移动牌3,发现b[4]、b[5]都是1(说明4和5已经移动过好了),也就是说4,5已经放到了6的下边,那么3可以直接放到6的下边,也就是6.5.4.3