日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

洛谷 P1242 新汉诺塔

發布時間:2024/4/17 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷 P1242 新汉诺塔 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原題鏈接

題目描述

設有n個大小不等的中空圓盤,按從小到大的順序從1到n編號。將這n個圓盤任意的迭套在三根立柱上,立柱的編號分別為A、B、C,這個狀態稱為初始狀態。

現在要求找到一種步數最少的移動方案,使得從初始狀態轉變為目標狀態。

移動時有如下要求:

·一次只能移一個盤;

·不允許把大盤移到小盤上面。

輸入輸出格式

輸入格式:

?

文件第一行是狀態中圓盤總數;

第二到第四行分別是初始狀態中A、B、C柱上圓盤的個數和從上到下每個圓盤的編號;

第五到第七行分別是目標狀態中A、B、C柱上圓盤的個數和從上到下每個圓盤的編號。

?

輸出格式:

?

每行一步移動方案,格式為:move I from P to Q

最后一行輸出最少的步數。

?

輸入輸出樣例

輸入樣例#1:?
5 3 3 2 1 2 5 4 0 1 2 3 5 4 3 1 1 輸出樣例#1:?
move 1 from A to B move 2 from A to C move 1 from B to C move 3 from A to B move 1 from C to B move 2 from C to A move 1 from B to C 7

說明

圓盤總數≤45

每行的圓盤描述是從下到上的圓盤編號

?

題解

這道題目是經典的漢諾塔問題,沒什么技術,但思維難度較高,如果條件判斷太多則編碼難度也會較高

?

首先,我們很容易想到一種假算法:(一定要注意它是錯的,但對真算法有啟發意義)

因為大盤子無法在小盤子上移動,而大盤子移動好之后又不會影響小盤子(這是本題所有操作的前提),故可以從大盤子開始移動。

我們從第N號盤子開始操作,計當前盤子為i號,如果它在原位置,那么就跳過,否則就將1~i-1號盤子都移動到不會動用的盤子,將目標盤子空出,然后將i號盤子放進去。經過N次操作,一定可以完成,但不能保證最優。

如圖所示,如果我們要將第1號樁上的1個大盤子移到2號樁,那么我們就先將1、2號樁上所有比i號盤子小的盤子都移到第3號樁

?

實現這一過程很簡單,只要每次將1~i-1號盤子移動到閑置的位置,然后移動即可,代碼也十分簡單

1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int INF=1e9+7,MAXN=50; 5 int N,cur[MAXN],goal[MAXN],ans; 6 char tran[]={' ','A','B','C'};/*translate*/ 7 inline void input(int *array,int opt){ 8 int ii,jj; 9 scanf("%d",&ii); 10 while(ii--){ 11 scanf("%d",&jj); 12 array[jj]=opt; 13 } 14 } 15 void dfs(int from/*from idx*/,int to/*to pos*/){/*move the "from"-th plate to position "to"*/ 16 if(cur[from]==to) 17 return; 18 int other=6-cur[from]-to; 19 for(int i=from-1;i>=1;i--) 20 dfs(i,other); 21 printf("move %d from %c to %c\n",from,tran[cur[from]],tran[to]); 22 cur[from]=to; 23 ans++; 24 } 25 int main(){ 26 scanf("%d",&N); 27 input(cur,1); 28 input(cur,2); 29 input(cur,3); 30 input(goal,1); 31 input(goal,2); 32 input(goal,3); 33 34 for(int i=N;i>=1;i--) 35 dfs(i,goal[i]); 36 printf("%d",ans); 37 return 0; 38 } View Code

?

但正如上面所說的,這是一個假算法。我們認定如圖的變換方法是正確的,是建立在漢諾塔的性質的基礎上的。在漢諾塔中,未歸位的盤子都是連續疊加的(如下圖1),不可能出現如圖2的情況

這樣的話,無論將這個連續的塔從哪里移動到哪里都是等價的,故開始給出的假算法是成立的。

然而可惜的是,我們的塔最初是隨機擺放的,所以會有另一種方法

可以證明,沒有其他移動方法了。但是否每次都要用兩種方法呢?顯然不是。觀察兩個圖組可以發現,在進行了一次操作后,就還原到了漢諾塔的基本結構:一串連續的盤子,就可以用常規的方法操作了。

那圖組2和圖組1的過程又怎么實現呢?我們需要三種操作

  • move(idx,from,to):當1~idx在同一個樁子上時,將它們移到to號樁子
  • merge(idx,to):當1~idx不在同一個樁子上時,將它們移到to號樁子
  • solve(idx,to):當1~idx歸位
  • move函數的實現很簡單,遞歸將1~idx-1號盤子移到閑置的位置,將idx號盤子移到to,再將1~idx-1號盤子移到to即可

    void mov(int idx,int from,int to,int other){ /*move 1~"idx"-th to "to" in a heap*/if(!idx)return;mov(idx-1,from,other,to);ans[st][++sz[st]]=(state){idx,from,to};mov(idx-1,other,to,from); }

    ?

    merge函數也不難,將遞歸將1~idx-1號盤子移到閑置的位置(用merge),將idx號盤子移到to,再將1~idx-1號盤子移到to即可(用move)

    void merg(int idx,int to){ /*move 1~"idx"-th to "to" not in a heap*/if(!idx)return;if(cur[idx]==to)return merg(idx-1,to);int other=6-cur[idx]-to;merg(idx-1,other);ans[st][++sz[st]]=(state){idx,cur[idx],to};mov(idx-1,other,to,cur[idx]); }

    ?

    solve函數的思想同上

    void solve(int idx,int to){ /*put 1-"idx"-th into its place*/if(!idx)return;if(goal[idx]==to)return solve(idx-1,to);int other=6-goal[idx]-to;mov(idx-1,to,other,goal[idx]);ans[st][++sz[st]]=(state){idx,to,goal[idx]};solve(idx-1,other); }

    ?

    有了這些操作,解題就很簡單了,我們按照上面講的兩種情況分類,輸出步數較少的方案即可

    void work(int idx){if(!idx)return;if(cur[idx]==goal[idx])return work(idx-1);int other=6-cur[idx]-goal[idx];/*0:all to other, N to to*/st=0;merg(idx-1,other);ans[st][++sz[st]]=(state){idx,cur[idx],goal[idx]};solve(idx-1,other);/*1:all to to, N to other, all to from, N to to*/st=1;merg(idx-1,goal[idx]);ans[st][++sz[st]]=(state){idx,cur[idx],other};mov(idx-1,goal[idx],cur[idx],other);ans[st][++sz[st]]=(state) {idx,other,goal[idx]};solve(idx-1,cur[idx]); }

    ?

    最終給出AC代碼

    1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int INF=1e9+7,MAXN=50,MAXP=1e5; 5 int N,cur[MAXN],goal[MAXN],cnt; 6 char tran[]={'E','A','B','C'};/*translate*/ 7 inline void input(int *array,int opt){ 8 int ii,jj; 9 scanf("%d",&ii); 10 while(ii--){ 11 scanf("%d",&jj); 12 array[jj]=opt; 13 } 14 } 15 struct state{ int idx,from,to; }ans[2][MAXP]; 16 int st,sz[2]; 17 void mov(int idx,int from,int to,int other){ 18 /*move 1~"idx"-th to "to" 19 in a heap*/ 20 if(!idx) 21 return; 22 mov(idx-1,from,other,to); 23 ans[st][++sz[st]]=(state){idx,from,to}; 24 mov(idx-1,other,to,from); 25 } 26 void merg(int idx,int to){ 27 /*move 1~"idx"-th to "to" 28 not in a heap*/ 29 if(!idx) 30 return; 31 if(cur[idx]==to) 32 return merg(idx-1,to); 33 int other=6-cur[idx]-to; 34 merg(idx-1,other); 35 ans[st][++sz[st]]=(state){idx,cur[idx],to}; 36 mov(idx-1,other,to,cur[idx]); 37 } 38 void solve(int idx,int to){ 39 /*put 1-"idx"-th into its place*/ 40 if(!idx) 41 return; 42 if(goal[idx]==to) 43 return solve(idx-1,to); 44 int other=6-goal[idx]-to; 45 mov(idx-1,to,other,goal[idx]); 46 ans[st][++sz[st]]=(state){idx,to,goal[idx]}; 47 solve(idx-1,other); 48 } 49 void work(int idx){ 50 if(!idx) 51 return; 52 if(cur[idx]==goal[idx]) 53 return work(idx-1); 54 int other=6-cur[idx]-goal[idx]; 55 /*0:all to other, N to to*/ 56 st=0; 57 merg(idx-1,other); 58 ans[st][++sz[st]]=(state){idx,cur[idx],goal[idx]}; 59 solve(idx-1,other); 60 /*1:all to to, N to other, all to from, N to to*/ 61 st=1; 62 merg(idx-1,goal[idx]); 63 ans[st][++sz[st]]=(state){idx,cur[idx],other}; 64 mov(idx-1,goal[idx],cur[idx],other); 65 ans[st][++sz[st]]=(state) {idx,other,goal[idx]}; 66 solve(idx-1,cur[idx]); 67 } 68 int main(){ 69 scanf("%d",&N); 70 input(cur,1); 71 input(cur,2); 72 input(cur,3); 73 input(goal,1); 74 input(goal,2); 75 input(goal,3); 76 77 work(N); 78 79 for(int i=1,ed=min(sz[0],sz[1]),j=sz[0]>sz[1];i<=ed;i++) 80 printf("move %d from %c to %c\n",ans[j][i].idx,tran[ans[j][i].from],tran[ans[j][i].to]); 81 printf("%d",min(sz[0],sz[1])); 82 return 0; 83 } View Code

    轉載于:https://www.cnblogs.com/guoshaoyang/p/11114054.html

    總結

    以上是生活随笔為你收集整理的洛谷 P1242 新汉诺塔的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。