同題:UVa 11716 – Digital Fortress
上一屆的 IIUPC 有一題「達文西密碼」是以丹布朗的暢銷書「達文西密碼」為故事背景。這一題則是以科技驚悚小說「數位堡壘」為背景。題目給你一個密文,你要用下述的解碼方式來解碼。
比如說,如果密文如下:
WECGEWHYAAIORTNU
輸出則是:
WEAREWATCHINGYOU
上例中所給的密文「WECGEWHYAAIORTNU」有 16 個字元,也就是 4 的平方。請把這些字元以「列優先」(row major,第一列放滿後再放第二列,再第三列……) 的方式置入一個 N*N (本例為 4*4) 的格子。本例密文放置完成後的格子如下:
W E C G
E W H Y
A A I O
R T N U
當我們以「行優先」(column major,取完第一行再取第二行,然後第三行) 的方式將上面格子的字元取出便可以得到以下的明文:
「WEAREWATCHINGYOU」
範例測資
範例輸入 | 範例輸出 |
---|---|
輸入的第一行有一個數字 T,接著有 T 筆測資,每筆測資一行,該行便是要處理的密文。密文僅包含大寫字母及空白。密文的總字元數不會超過 10,000。 | 相對於每筆測資,請將明文輸出於一行。若輸入的字元數不是完全平方數,請輸出「INVALID」。 |
3 WECGEWHYAAIORTNU DAVINCICODE DTFRIAOEGLRSI TS | WEAREWATCHINGYOU INVALID DIGITAL FORTRESS |
解題思路
測資中會有包含空白字元的字串,所以在收完 T 之後要使用 cin.ignore() 才能使用 getline。
可以先判斷字串的長度是否為完全平方數,如果 pow(sqrt(字串長度), 2),也就是字串長度根號的平方,為字串長度的話,就代表字串長度為完全平方數。
可以宣告一個 Vector<string> 來存處理後的字串,並且宣告一個變數 square 為字串長度的根號。跑兩層 square 的 For迴圈,並且預設一個 count 變數為 0,每次將 字串[count] 加到一個暫存字串,並且將 count++,每當內層 For迴圈 結束時就將暫存字串 Push_Back 到 Vector<string> 中。
輸出時一樣要跑兩層 square 的 For迴圈,這邊簡稱第一層為 j 迴圈,第二層為 k 迴圈,每次在 k 迴圈中輸出 Vector<string> 的 [k][j]。第一層迴圈結束之後換行就結束了。
範例程式碼-ZeroJudge D671: Digital Fortress
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
int main() {
cin.sync_with_stdio(0);
cin.tie(0);
int N;
cin >> N;
cin.ignore();
for (int i = 0; i<N; i++) {
string str;
getline(cin, str);
const int len = int(str.length()), square = int(sqrt(len));
if (pow(square, 2) != len) {
cout << "INVALID\n";
continue;
}
vector<string>v;
int count = 0;
for (int j = 0; j<square; j++) {
string tmp = "";
for (int k = 0; k<square; k++) {
tmp += str[count];
count++;
}
v.push_back(tmp);
}
for (int j = 0; j<square; j++) {
for(int k = 0; k<square; k++) cout << v[k][j];
}
cout << "\n";
}
}
//ZeroJudge D671
//Dr. SeanXD