HDU - 1584 蜘蛛牌(dfs+最优性剪枝)
題目鏈接:點擊查看
題目大意:給出10張牌,隨機分布在1~10十個不同的位置,要求模擬蜘蛛紙牌的游戲規則,問移動的最短距離之和是多少
題目分析:我們可以直接dfs搜索,但需要想清楚該怎么搜索,這個題目有點貪心的思想,因為要求移動距離之和最小,所以我們應該盡量避免多余的移動,簡單來說,我們只需要將當前牌放置到比當前牌序號大1的牌上就行,說起來可能有些抽象,舉個例子,牌1只需要移動到牌2上即可,不需要移動到牌3上然后再移動到牌2上之類的,相對的,牌10的位置就固定了,因為牌10在哪里都一樣。
然后就是搜索了,因為不一定是按照順序來的,不一定是牌1放到牌2上,然后牌2帶著牌1放到牌3上,也可能是牌2先放到牌3上,然后牌1再放到牌2上等等等等,所以我們在搜索時,第一層for需要枚舉所當前輪次所需要移動的牌,然后第二層for需要尋找比當前牌序號大1的牌的位置,然后放上去即可,一開始我就是不太會處理第二層for循環,以為單純的用i+1來判斷就行,果不其然的WA了一發,其實可以換個思想,比如我們已經將牌4放到牌5上了,那么我們接下來需要將牌3放到牌4上,我們該處理的距離肯定不是abs(a[3]-a[4])了,因為此時的牌4已經到了牌5的位置,所以正確距離應該是abs(a[3]-a[5])才對,所以我們的vis數組保存的是每一堆撲克中最底層的那個牌的大小,并且根據規則,我們可以保證這個牌的序號一定是該堆牌中最大的一張,所以我們在尋找目標牌的位置時,只需要在i+1-10中找到第一個在最底層的數即可,假設我們找到的目標牌是k,則可以保證第i+1~k張牌已經放到了第k張牌的上面
emmm,可能理解起來有點麻煩,但畢竟也是我想了有一個小時才想明白的問題。。直接掛代碼吧,和網上絕大部分的代碼一樣:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=15;int a[N];int ans;bool vis[N];void dfs(int pos,int cnt) {if(cnt>=ans)//最優性剪枝return;if(pos==9)//若所有牌的情況都處理完畢,更新結果{ans=cnt;return;}for(int i=1;i<10;i++)//選擇需要移動的牌{if(!vis[i]){vis[i]=true;for(int j=i+1;j<=10;j++)//找目標牌的位置if(!vis[j]){dfs(pos+1,cnt+abs(a[i]-a[j]));break;}vis[i]=false;}} }int main() { // freopen("input.txt","r",stdin);int w;cin>>w;while(w--){for(int i=1;i<=10;i++){int num;scanf("%d",&num);a[num]=i;}memset(vis,false,sizeof(vis));ans=100;//答案初始化為100,其實到90就行,強迫癥湊個整dfs(0,0);printf("%d\n",ans);}return 0; }?
總結
以上是生活随笔為你收集整理的HDU - 1584 蜘蛛牌(dfs+最优性剪枝)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ - 3700 Missile D
- 下一篇: POJ - 1011 Sticks(df