Google Code Jam 2009 - Qualification Round
Code Jam - Google’s Coding Competitions
参戦記録として書いておく。
結果は約1時間半で全問解けて、65位。それぞれ30分ぐらいずつかかった。出だし好調と言える結果だが、全問解いた方は約2400人もいる。Round 1の合計通過人数が3000人なので、Round 1を通過するだけでも大変そうだ。
以下、適当な解説と書いたプログラムのソースコード。
Problem A. Alien Language
宇宙人のメッセージを解読。簡単な正規表現。実際、正規表現をサポートしている言語を使って問題を解いた参加者もいたみたいだ。僕は、メッセージの一文字ごとの候補を作り、それをwordの文字と比較して、表現できるかどうかを調べた。
#include <iostream> #include <set> #include <vector> #include <string> #include <sstream> #include <cstdio> using namespace std; int main(void) { int L, D, N; string line; getline(cin, line); istringstream iss(line); iss >> L >> D >> N; set<string> words; while (D-- > 0) { getline(cin, line); words.insert(line); } for (int caseNo = 1; caseNo <= N; caseNo++) { getline(cin, line); istringstream iss2(line); vector<string> token(L, ""); bool isInPara = false; char c; int i = 0; while (iss2 >> c) { if (c == '(') { isInPara = true; } else if (c == ')') { isInPara = false; i++; } else if (isInPara) { token[i] += string(1,c); } else { token[i] = string(1,c); i++; } } int K = 0; for (set<string>::const_iterator wd = words.begin(); wd != words.end(); wd++) { for (int i = 0; i < L; i++) { if (token[i].find((*wd)[i]) == string::npos) break; if (i == L-1) { K++; break; } } } printf("Case #%d: %d\n", caseNo, K); } return 0; }
Problem B. Watersheds
どこに水がたまるか。シミュレーション。再帰で解いた。1回調べたマスはもう調べないようにして計算量を削減した。
#include <iostream> #include <vector> #include <cstdio> using namespace std; int H, W; vector<vector<int> > basin; vector<vector<char> > sink; char go(const int y, const int x, const char label) { static int d[4][2] = { {-1, 0}, { 0,-1}, { 0, 1}, { 1, 0} }; if (sink[y][x] != '?') return sink[y][x]; int lowest = -1; int lowestApptitude = INT_MAX; for (int i = 0; i < 4; i++) { const int dy = y + d[i][0]; const int dx = x + d[i][1]; if (0<=dy&&dy<H && 0<=dx&&dx<W && basin[dy][dx] < lowestApptitude && basin[dy][dx] < basin[y][x]) { lowest = i; lowestApptitude = basin[dy][dx]; } } if (lowest == -1) { sink[y][x] = label; } else { sink[y][x] = go(y+d[lowest][0],x+d[lowest][1],label); } return sink[y][x]; } int main(void) { int T; cin >> T; for (int caseNo = 1; caseNo <= T; caseNo++) { cin >> H >> W; basin = vector<vector<int> >(H, vector<int>(W)); sink = vector<vector<char> >(H, vector<char>(W,'?')); for (int y = 0; y < H; y++) for (int x = 0; x < W; x++) cin >> basin[y][x]; char label = 'a'; for (int y = 0; y < H; y++) for (int x = 0; x < W; x++) if (sink[y][x] == '?') { if (go(y, x, label) == label) label++; } printf("Case #%d:\n", caseNo); for (int y = 0; y < H; y++) for (int x = 0; x < W; x++) { cout << sink[y][x]; if (x == W-1) cout << endl; else cout << " "; } } return 0; }
Problem C. Welcome to Code Jam
文字列中に"welcome to code jam"が何個隠れているかを数える。入力例があまり親切とは言えなく、どういう問題だと解釈すればいいのか迷った。通ったので解釈はあっていたのだと思う。だけど、このプログラム、余計な処理を行っている気がする。気が向いたら削れるかどうかを考える。
#include <iostream> #include <string> #include <sstream> #include <vector> using namespace std; int main(void) { string line; getline(cin, line); int N; istringstream(line) >> N; const string message = "welcome to code jam"; const int mesLen = message.length(); for (int caseNo = 1; caseNo <= N; caseNo++) { int counter = 0; getline(cin, line); const int lineLen = line.length(); vector<vector<int> > memo(lineLen,vector<int>(mesLen,0)); for (int i = 0; i < lineLen; i++) if (line[i] == message[0]) memo[i][0] = 1; for (int i = 0; i < lineLen; i++) { for (int j = mesLen-1; j > 0; j--) { if (line[i] != message[j]) continue; for (int k = 0; k < i; k++) memo[i][j] += memo[k][j-1]; memo[i][j] %= 10000; } } for (int i = 0; i < lineLen; i++) { counter += memo[i][mesLen-1]; counter %= 10000; } printf("Case #%d: %04d\n", caseNo, counter); } return 0; }