hdu1584 蜘蛛牌(經典dfs)
阿新 • • 發佈:2019-01-02
真是好題啊。。。
剛開始一看下一個狀態是由上一個子問題得來的,想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 <stdio.h> #include <algorithm> #include <string.h> #include <iostream> #include <stdlib.h> 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; }