HDU1430,魔板
書上的推薦例題,在雙向廣搜裡面。剛開始嘗試用雙向廣搜,但是一直wa,看網上討論才知道所得到的答案不一定是最小的字典序。此題比較糾結的是標記,普通做要開8維陣列,但是如果用cantor展開之後,每一種狀態就可以用一個數字來代表,只用一個一維陣列就可以標記了。
另外,要對輸入做一下處理:將每一組的初態變成”12345678”,然後末態相應地變成“xxxxxxxx”,這樣一來,每次的初態都一樣,只是末態不一樣,一次bfs()將所有的情況的結果都打表,然後每輸入一個末態,直接輸出答案,這樣才不會超時。現在的問題是:初態變成”12345678“之後,怎樣將末態變成相應的”xxxxxxxx”,答案才不會錯。舉個例子:比如初態是“63728145”,將初態處理成“12345678”之後,發生的改變是6->1,3->2,7->3,2->4,8->5,1->6,4->7,5->8假若末態為“54716328”,由於初態發生了改變,所以末態也要依照相同的規則進行改變,所以末態應該變為“54716328”->”87361245”,程式碼的實現為:
注:start[8]是初態,end[8]是末態,f[8]是對應的變換的值,比如上面就是f[6]=1
//處理f[8]陣列
for (int i=0; i<8; i++)
{
f[start[i]]=i+1;//上面就是f[6]=1,f[3]=2等等
}
//處理end[8]陣列,start[8]不用管了,直接就是12345678
for (int i=0; i<8; i++)
{
end[i]=f[end[i]];//原來是多少,按照f(x)進行變換
}
做好了上面的工作,下面的,應該問題就不大了,程式碼如下:
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年08月31日 星期五 14時21分37秒
> Description:HDU1430
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<string>
#include<algorithm>
using namespace std;
int factorial[]={1,1,2,6,24,120,720,5040,40320};//階乘
bool vis[46300];//標記陣列
string ans[46300];//打表
struct node
{
char nums[2][4];//八個數字,我用的是char
string s;//儲存操作A、B、C
void A()//A操作,下同
{
for (int i=0; i<4; i++)
{
char tmp=nums[0][i];
nums[0][i]=nums[1][i];
nums[1][i]=tmp;
}
s+='A';
}
void B()
{
char tmp1=nums[0][3];
char tmp2=nums[1][3];
for (int i=3; i>0;i--)
{
nums[0][i]=nums[0][i-1];
nums[1][i]=nums[1][i-1];
}
nums[0][0]=tmp1;
nums[1][0]=tmp2;
s+='B';
}
void C()
{
char tmp=nums[0][1];
nums[0][1]=nums[1][1];
nums[1][1]=nums[1][2];
nums[1][2]=nums[0][2];
nums[0][2]=tmp;
s+='C';
}
int cantor()//獲得cantor值,就好比人的身份證,每個狀態都只有唯一的值
{
int val=0;
char tmp[8];
for (int i=0; i<4; i++)
tmp[i]=nums[0][i];
for (int i=3; i>=0; i--)
tmp[7-i]=nums[1][i];
for (int i=0; i<7; i++)
{
int smaller=0;
for (int j=i+1; j<8; j++)
if(tmp[i]>tmp[j])
smaller++;
val+=smaller*factorial[8-1-i];
}
return val;
}
}s,e,cur,nex;//s是開始,e是結束,cur是當前,nex是下一個
void bfs()
{
memset(vis,false,sizeof(vis));
vis[s.cantor()]=true;
ans[s.cantor()]='\n';
queue<node>Q;
Q.push(s);
while (!Q.empty())
{
cur=Q.front();
Q.pop();
for (int i=0; i<3; i++)
{
nex=cur;
switch(i)
{
case 0:
nex.A();break;
case 1:
nex.B();break;
case 2:
nex.C();break;
}
if(!vis[nex.cantor()])
{
vis[nex.cantor()]=true;
ans[nex.cantor()]=nex.s;
Q.push(nex);
}
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
char tmp[9];
//使s的八個數字為"12345678"
for (int i=0; i<4; i++)
s.nums[0][i]=i+1+'0';
for (int i=3; i>=0; i--)
s.nums[1][i]=8-i+'0';
bfs();
while (cin>>tmp)
{
int f[9];
for (int i=0; i<8; i++)
f[tmp[i]-'0']=i+1;
cin>>tmp;
//使e的八個數字相應地改變
for (int i=0; i<4; i++)
e.nums[0][i]=f[tmp[i]-'0']+'0';
for (int i=3; i>=0; i--)
e.nums[1][i]=f[tmp[7-i]-'0']+'0';
if (e.cantor()==0)
cout<<endl;
else
cout<<ans[e.cantor()]<<endl;
}
return 0;
}
我當時還有一點比較疑惑,就是怕答案中出現類似”AA”,”BBBB”,”CCCC”的東西,但實際上不會出現,因為:出現AA,BBBB,CCCC,就回到上一步操作了,而上一步的vis[]陣列已經被標記了,所以不會出現此類情況。
相關文章
- 魔板引擎中的replace方法
- 魔搭社群
- 魔術方法
- PHP 魔術方法PHP
- 公告板
- 致“逝去”的《魔獸》
- 十六個魔術方法
- php 魔術方法 __callPHP
- PHP中什麼是魔術常量?有哪些魔術常量?(總結)PHP
- 魔鏡魔鏡,今天有雨嗎?——GitHub 熱點速覽 v.21.25Github
- 留言板
- 魔功心法-列舉篇
- 魔都的旅遊攻略
- PHP 魔術常量簡要PHP
- 蟻劍原理與魔改
- #魔術方法(會話管理)會話
- 主機板定製中X86主機板和ARM主機板的比較
- 何為打板
- SVG <mask>蒙板SVG
- P1481 魔族密碼密碼
- 《魔獸世界》的“中年危機”?
- FC《惡魔城》系列追憶
- R:魔獸世界終極版
- 魔改redis之新增命令hrandmemberRedis
- 魔獸世界之一:備戰
- “魔獸”玩家小心啦! Lucky蠕蟲病毒利用魔獸地圖大肆傳播地圖
- 紅魔Mars電競手機支援NFC功能嗎?紅魔Mars有沒有NFC功能
- 🚀2023最新版克魔助手抓包教程(9) - 克魔助手 IOS 資料抓包iOS
- w10魔獸全屏設定方法_魔獸爭霸3win10怎麼全屏Win10
- 努比亞紅魔Mars電競手機評測 紅魔Mars手機怎麼樣?
- 努比亞紅魔遊戲手機評測 紅魔遊戲手機值得買嗎?遊戲
- 新三板怎麼買 新三板參與流程
- Datawhale X 魔搭 AI夏令營(三)AI
- 類銀河惡魔城——角色操作
- 繼承關係和魔術方法繼承
- 銀河惡魔城入門指南
- Kotlin的魔能機甲——KtArmor(三)Kotlin
- PHP 物件導向 (六)魔術方法PHP物件