IOI 96 Magic Square解題報告

2022-09-04 04:39:10 字數 2770 閱讀 5136

ioi『96 magic square(魔版)

題目由jerryxie翻譯。

magic square(msqaure.cpp/c/pas)

【問題描述】

在魔方的成功之後,盧比克先生發明了它的二維版本,叫做魔版。它是乙個由八個方塊組成的**。

在本題中我們認為每乙個方塊都有不同的顏色,這些顏色將會用1~8共8個整數表示。乙個**的狀態將會以乙個由顏色組成的序列表示,順序是從**左上角沿順時針方向給出。比如上面這個**,序列為(1,2,3,4,5,6,7,8),這被稱作初始狀態。

魔版有三種基本變換,用'a', 'b', 'c'表示,可以改變魔版的狀態。

a:將第一行和第二行交換;

b:將最右側的一列插入最左側;

c:將中間兩列沿順時針旋轉90度。

下面是對初始狀態的三種變化:

所有可能的狀態都能使用這三種基本變換。

你需要編寫乙個程式來計算從初始狀態變化為指定狀態所需要的最短的操作序列。

【輸入】

輸入檔名為msquare.in。

輸入檔案只有一行,共有8個數,每個數用空格隔開,為指定狀態的顏色序列(用1~8表示)。

【輸出】

輸出檔名為msquare.out。

line 1::乙個整數,表示最短的操作序列的長度。

line 2:是字典序中最早出現的操作序列。除最後一行外每行60個字元。

【輸入輸出樣例】

msquare.in

msquare.out

2 6 8 4 5 7 3 1 

7bcabccb

【題目分析】

分析題目,我們可以發現這完全可以用bfs解決。而且要求輸出字典序第乙個序列,這樣我們可以通過bfs搜尋到第乙個解就可以退出搜尋。搜尋方法是:從初始狀態開始,分別進行a,b,c三種操作得到三個狀態然後進入佇列,再從隊頭取出乙個狀態重複上述操作,最終找到解。而操作序列的長度則為搜尋所得出的解的結點在解答樹中的深度(根節點即初始狀態深度為0)。而判重則可以使用康托展開處理,用標記陣列標記此狀態是否已經搜尋過,如果搜尋過則不入隊,在入隊的過程中我們需要記錄一下當前的操作和父結點,方便返回時能夠輸出操作序列。還有,我們從輸出格式中的line2發現可能序列不止一行,而在測試後我們發現最長的操作序列只有20多個操作,所以在下面給出的**中沒有涉及到60個字元換行的問題,如果需要可以在輸出的位置進行補充。

【程式源**】

by jerryxie   

#include

using namespace std;   

struct queue //定義結構體用來表示佇列    

q[50001];   

int a[10],direct[10],bin[11],original[10];   

bool had[50001]; //判重標記陣列    

void operation(char c) //執行a~c三種操作    

else if(c=='b')   

else if(c=='c')   

else;   

}   

void create() //初始化初始狀態和0~10的階乘值    

int xtonum(int x) //把排列轉換為值(康托展開)    

,i,j,num=0;   

for(i=1;i<=8;i++)   

for(j=i+1;j<=8;j++)   

if(x[i]>x[j])   

b[i]++;   

for(i=1;i<=8;i++)   

num+=b[i]*bin[8-i];   

return num;   

}   

void translate(int b) //把計算出的排列轉換為原始排列    

}   

}   

}   

void numtoa(int num) //把值轉換為排列(逆康托展開)    

b[8]=0;   

translate(b);   

return;   

}   

bool ishad(int num) //判重,判斷佇列中是否存在當前值,如果有則視為已經擴充套件過此結點,不需入隊進行擴充套件    

void print(int qnail) //輸出解    

printf("%d\n",onum); //輸出序列長度    

for(i=onum;i>=1;i--) //輸出操作序列,由於記錄是從解的結點逆推回根結點的,所以輸出也應逆過來,表示從根結點到解的結點的操作序列    

printf("%c",o[i]);   

printf("\n"); //換行符(usaco要求輸出檔案最後應有乙個空行)    

return;   

}   

int main()   

else //如果不是則入隊    

while(sign) //開始搜尋    

else //如果不相同    

}   

if(c=='a' || c=='b') //如果變換操作為a~b則使a陣列還原為未變換之前的狀態,以進行下乙個操作    

for(i=1;i<=8;i++)   

a[i]=original[i];   

}   

qhead++; //擴充套件後出隊    

}   

return 0;   

}   

本程式在usaco上測試通過。

歡迎鄙視。

IOI96 最長字首

時間限制 15000 ms 空間限制 65536 kb 問題描述 在生物學中,一些生物的結構是用包含其要素的大寫字母序列來表示的。生物學家對於把長的序列分解成較短的序列 即元素 很感興趣。如果乙個集合 p 中的元素可以通過串聯 元素可以重複使用,相當於 pascal 中的 運算子 組成乙個序列 s ...