题目链接:
http://soj.sysu.edu.cn/1016
题目大意:
给定一个字符串和256条规则,将某条规则应用于字符串,字符串将发生变化,给定一个数max,求出在max步内可以将字符串变为指定字符串的规则号以及步数。
题目分析:
既然只有256条规则,而且步数又有限制,那我们就暴力模拟,把所有情况都求出来就行了,但是如果用原始字符串来做是非常慢的,虽然题目的时间限制很宽松(10s),但也是会超时的。所以对于每个规则我用一个record的map来保存已经遇到过的字符串,这样就可以过了(虽然还是很慢)。
在网上看到的做法是用0,1分别代表白黑的,而且用到了很多位运算,虽然也是暴力,但是快很多,一样的测试,人家0.15s就过了。
代码:
// Problem#: 1016 // Submission#: 3585804 // The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License // URI: http://creativecommons.org/licenses/by-nc-sa/3.0/ // All Copyright reserved by Informatic Lab of Sun Yat-sen University #include <stdio.h> #include <string.h> // int rule[256][8], m[15]; long long step, length; char num[20], target[300]; int targetNum[300], pro[2][300]; int answerNum, ans1[300], ans2[300]; int MAX() { if (length < 11) return m[length]; else return 985; } void init() { for (int i = 0; i < 256; i++) { int temp = i; for (int j = 0; j < 8; j++) { rule[i][j] = temp & 1; temp >>= 1; } } m[0] = 1; for (int i = 1; i < 11; i++) m[i] = m[i - 1] << 1; } bool check() { length = strlen(target); if (length < 3) return false; for (int i = 0; i < length; i++) { if (target[i] == 'W') targetNum[i] = 0; else if (target[i] == 'B') targetNum[i] = 1; else return false; } if ((targetNum[0] == 1) || (targetNum[length - 1] == 1) || (length & 1 == 0)) return false; return true; } int main() { init(); int caseNum = 1; while (1) { scanf("%s%s", num, target); if (strcmp(num, "END") == 0) break; printf("LINE %d ", caseNum++); if (!check()) { printf("NONE\n"); continue; } step = 0; for (int i = 0; num[i] != '\0'; i++) step = step * 10 + num[i] - '0'; if (step > MAX()) step = MAX(); answerNum = 0; for (int i = 0; i < 256; i++) { memset(pro, 0, sizeof(pro)); int last = 0, now = 1; int s = 1; int jlength = length - 2, ruleNum; pro[now][length / 2] = 1; while (1) { if (s > step) break; bool isSame = true; for (int k = 0; k < length; k++) { if (pro[now][k] != targetNum[k]) { isSame = false; break; } } if (isSame) { ans1[answerNum] = i; ans2[answerNum] = s; answerNum++; break; } now ^= 1; last ^= 1; s++; for (int j = 0; j < jlength; j++) { ruleNum = pro[last][j]; ruleNum <<= 1; ruleNum += pro[last][j + 1]; ruleNum <<= 1; ruleNum += pro[last][j + 2]; pro[now][j + 1] = rule[i][ruleNum]; } pro[now][0] = pro[now][length - 1] = 0; } } if (answerNum) { for (int i = 0; i < answerNum; i++) printf("(%d,%d)", ans1[i], ans2[i]); printf("\n"); } else printf("NONE\n"); } return 0; }
这提示我以后能用int尽量不用字符串。多考虑效率。这道题要是时间限制到1s我就GG了。
我的代码:
#include <iostream> #include <map> #include <vector> #include <string.h> using namespace std; struct Ans { int mo, t; Ans(){} Ans(int a, int b) { mo = a; t = b; } }; //0 for white, 1 for black int model[9]; map<string, int> transfer; map<string, int> record; vector<Ans> ans; int Max; string line; string ary, dest, ary2; int l; void addModel() { int i = 8, j; while (i >= 0 && model[i]) { i--; } for (j = i; j <= 8; j++) { model[j] = 1-model[j]; } } int toInt(string tmp) { int i, tot = 0; for (i = 0; i < tmp.length(); i++) { tot = tot*10 + tmp[i] - '0'; } return tot; } void getData(int& n, string& r) { string tmp1, tmp2; tmp1 = tmp2 = ""; int i; for (i = 0; r[i] != ' '; i++) { tmp1 += r[i]; } for (i++; i<r.length(); i++) { tmp2 += r[i]; } n = toInt(tmp1); dest = tmp2; l = dest.length(); } bool cut(int f) { string tmp; int i; for (i = 0; i < 3; i++) { tmp += ary2[f+i]; } return model[transfer[tmp]]; } void Do() { int i; ary2 = ary; for (i = 0; i < l-2; i++) { if (cut(i)) { ary[i+1] = 'B'; } else { ary[i+1] = 'W'; } } } bool equal(const string& a, const string& b) { int i; for (i = 0; i < l; i++) { if (a[i] != b[i]) { return false; } } return true; } int main() { transfer["BBB"] = 1; transfer["BBW"] = 2; transfer["BWB"] = 3; transfer["BWW"] = 4; transfer["WBB"] = 5; transfer["WBW"] = 6; transfer["WWB"] = 7; transfer["WWW"] = 8; int cnt = 0; while (getline(cin, line)) { cnt++; if (line == "END OF INPUT") break; ans.clear(); getData(Max, line); int i, j, k; for (i = 0; i < 256; i++) { ary = ""; for (k = 0; k < l; k++) { ary += 'W'; } ary[l/2] = 'B'; record.clear(); for (j = 0; j < Max; j++) { if (record[ary]) { break; } if (equal(ary, dest)) { ans.push_back(Ans(i, j+1)); break; } else { record[ary] = 1; } Do(); } addModel(); } cout << "LINE " << cnt << " "; for (i = 0; i < ans.size(); i++) { cout << "(" << ans[i].mo << "," << ans[i].t << ")"; } if (!ans.size()) { cout << "NONE"; } cout << endl; } }