hdu1584 蜘蛛牌(经典dfs)

真是好题啊。。。

刚开始一看下一个状态是由上一个子问题得来的,想DP上去了,结果找不出状态方程,一百度是数位DP,还是dfs吧= =。。。


这题的dfs也很奇葩,我对dfs理解还浅啊,刚开始怎么也想不到怎么用dfs还不在更新数组的情况下。于是。。。对我来说还是太难了T T

这题越想越牛逼,本来我还不服,怎么实现移动的牌按字典序?

我们来个例子,先是最简单的1,2,3,4顺序:

1上,标记1,看到2,递归;1被标记,2上,标记2,看到3 ,递归;1、2被标记,3上, 标记3, 看到4,递归;返回最优解。

再来2,1,3,4顺序:

1上,标记,看到2,递归;。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。此过程类似上面

第二次就不一样了!

2上,标记,看到3,递归;1未被标记,1上,标记1,看到3,递归。。。。。。。。。。。。。。。同类似

使用的牌按顺序字典序固然好理解,当打乱的时候同样是按照字典序,这就是对递归领悟境界的更高层次啊!


ps:语文不好还加点头晕(貌似要感冒)表达不好,不过我觉得这就是自己凭空想!谁都帮不了你,在脑海中模拟树的构造,这才是dfs的精髓!(个人理解勿喷)。。

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 100;
const int INF = 1000000;

char a[N], mark[N];
int ans;

void dfs(int num, int sum)
{
    if(sum >= ans) return;//剪枝
    if(num == 9)//刚开始我以为是大于9的解都被剪掉了,现在想这本来就是个9层树。。。
    {
        ans = sum;
        return;
    }
    for(int i = 1; i < 10; i ++)//最后一张牌除空位(已标记)外没有任何移动的地方,本语句代表现在准备移动(操作)哪张牌
    {
        if(!mark[i])
        {
            mark[i] = 1;
            for(int j = i + 1; j <= 10; j ++)//移动到哪个位置。注意这里不一定是移动到5号牌(打个比方)后的位置,也有可能是5号牌前的位置。因为每次dfs相当于生出一层树枝,而生出的树枝又是从1号牌开始操作,也就是说只要2、3、4号牌没被标记,还是有可能移动到这里,而移到这里的是1号牌而不是5号牌
            {
                if(!mark[j])
                {
                    dfs(num + 1, sum + abs(a[j] - a[i]));
                    break;//这里的直观意义就是下一层树枝返回,此牌所找的位置安放不对或寻求其他最优解,而for是为了遍历所有解,是一个意思,所以退出
                }
            }
            mark[i] = 0;//回溯
        }
    }
}

int main()
{
   // freopen("in.txt", "r", stdin);
    int T, x;
    scanf("%d", &T);
    while(T --)
    {
        for(int i = 1; i <= 10; i ++)
        {
            scanf("%d", &x);
            a[x] = i;//存储每张牌在哪个位置,比如6号牌在位置2
        }
        memset(mark, 0, sizeof(mark));
        ans = INF;
        dfs(0, 0);
        printf("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(数据结构-各种搜索)