虽然很多方法都一个意思……但是我因为算错2^27,认为爆int就没用位运算……然后傻呼呼的居然在压十进制位在做BFS……
在USACO上TLE,但是其他OJ一般卡时内能过……
9个数字分解为0123,然后用一个9位数保存…… 大量时间浪费在拆解数字上……
下面这个程序是无脑BFS的错误
/* TASK:clocks LANG:C++ */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <cstdlib> #include <map> using namespace std; const unsigned int plan[9][7] = { {4, 0, 1, 3, 4}, {3, 0, 1, 2}, {4, 1, 2, 4, 5}, {3, 0, 3, 6}, {5, 1, 3, 4, 5, 7}, {3, 2, 5, 8}, {4, 3, 4, 6, 7}, {3, 6, 7, 8}, {4, 4, 5, 7, 8} }; const unsigned int num[9] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; unsigned int a[9]; inline unsigned int do_chang(unsigned int *r) { unsigned int tmp = 0; for (int i = 0; i != 9; ++ i) tmp = tmp * 10 + r[i]; return tmp; } struct whole { unsigned int pre, output_buff; whole(unsigned int A = 0, unsigned int B = 0):pre(A), output_buff(B){} }; map<unsigned int, whole>G; map<unsigned int, whole>::iterator it; queue<unsigned int>Q; unsigned int x[9]; inline void output() { unsigned int ans[100], t = 0; int tmp = do_chang(a); for (int i = 0; i != tmp; i = G[i].pre) ans[++t] = G[i].output_buff; for (int i = t; i > 1; -- i) cout<<ans[i] + 1<<" "; cout<<ans[1] + 1<<endl; } unsigned int z[9]; int main() { freopen("clocks.in", "r", stdin); freopen("clocks.out", "w", stdout); for (int i = 0; i != 9; ++ i) { cin >> a[i]; a[i] = (a[i] / 3) % 4; } int tmp = do_chang(a); G[tmp] = 1; Q.push(tmp); int tot = 0; while (!Q.empty()) { ++tot; unsigned int now = Q.front(); Q.pop(); for (int i = 0; i != 9; ++ i) z[i] = x[i] = (now / num[i]) % 10; for (int i = 0; i != 9; ++ i) { for (int j = 1; j <= plan[i][0]; ++ j) { tmp = plan[i][j]; x[tmp] = (x[tmp] + 1) % 4; } tmp = do_chang(x); if (!tmp) { G[tmp] = whole(now, i); output(); return 0; } it = G.find(tmp); if (it == G.end()) //如果没有被使用过的情况,塞进队列 { G[tmp] = whole(now, i); Q.push(tmp); } for (int i = 0; i != 9; ++ i) x[i] = z[i]; } } return 0; }
过了一天……我写成位运算版本的了……效率提升了那么一点点一点点……看来思想有问题……(在USACO以外的OJ已经通过了……可惜USACO的测评机实在是专业让非正确算法不过……)
以下程序依旧是TLE
/* TASK:clocks LANG:C++ */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <cstdlib> #include <map> using namespace std; const unsigned int plan[9][7] = { {4, 0, 1, 3, 4}, {3, 0, 1, 2}, {4, 1, 2, 4, 5}, {3, 0, 3, 6}, {5, 1, 3, 4, 5, 7}, {3, 2, 5, 8}, {4, 3, 4, 6, 7}, {3, 6, 7, 8}, {4, 4, 5, 7, 8} }; typedef unsigned int ui; typedef pair<ui, ui> PUU; const ui mod = 76695844; const ui plus_one[9] = {16777216,2097152,262144,32768,4096,512,64,8,1}; ui a[9]={0}, origin; #define mp make_pair<ui, ui> queue<ui>Q; map<ui, PUU>G; map<ui, PUU>::iterator it; //G[i].first 前驱是谁 second使用的序号是什么 void output(ui k) { ui ans[50], t=0; for (;k!=origin;k = G[k].first) ans[++t] = G[k].second; for (ui i = t; i > 1; -- i) cout<<ans[i] + 1<<" "; cout<<ans[1] + 1<<endl; } int main() { freopen("clocks.in", "r", stdin); freopen("clocks.out", "w", stdout); ui tmp = 0, ta; for (int i = 0; i != 9; ++ i) { cin >> ta; ta = (ta / 3) % 4; tmp = tmp * 8 + ta; } for (int i = 0; i != 9; ++ i) for (int j = 1; j <= plan[i][0]; ++ j) a[i] |= plus_one[plan[i][j]]; Q.push(origin = tmp); G[tmp] = mp(0, 0); while (!Q.empty()) { ui now = Q.front(); Q.pop(); for (int i = 0; i != 9; ++ i) { tmp = ((now + a[i]) | mod) ^ mod; if (!tmp) { G[tmp] = mp(now, i); output(tmp); return 0; } it = G.find(tmp); if (it == G.end()) { G[tmp] = mp(now,i); Q.push(tmp); } } } }
好吧,上面的BFS改为DFS,稍微加剪枝就过了。
重新分析后得到,一个是DFS搜索的确可以剪枝,BFS不太好剪,第二个我BFS没有充分利用每个状态只能搜3次,而且使用了很傻×的map来判重。造成TLE的罪魁祸首就是MAP了。
下面的程序终于是AC的了,而且效率非常高,程序也比较短
Test 1: TEST OK [0.005 secs, 3372 KB] Test 2: TEST OK [0.003 secs, 3372 KB] Test 3: TEST OK [0.005 secs, 3372 KB] Test 4: TEST OK [0.003 secs, 3372 KB] Test 5: TEST OK [0.011 secs, 3372 KB] Test 6: TEST OK [0.005 secs, 3372 KB] Test 7: TEST OK [0.005 secs, 3372 KB] Test 8: TEST OK [0.008 secs, 3372 KB] Test 9: TEST OK [0.008 secs, 3372 KB]
/* TASK:clocks LANG:C++ */ #include <cstring> #include <cstdio> const unsigned int plan[9][6] = {{4, 0, 1, 3, 4},{3, 0, 1, 2},{4, 1, 2, 4, 5},{3, 0, 3, 6},{5, 1, 3, 4, 5, 7},{3, 2, 5, 8},{4, 3, 4, 6, 7},{3, 6, 7, 8},{4, 4, 5, 7, 8}}; typedef unsigned int ui; const ui mod = 76695844; const ui plus_one[9] = {16777216,2097152,262144,32768,4096,512,64,8,1}; ui a[9]={0},ans[9], ansbuff[9], opbuff[36],ot=0,ans_bu(50),tmp = 0, ta; int tot = 0; void dfs(ui now, ui deep, ui bu) { ++tot; if (bu >= ans_bu) return; if (deep == 9) { if (now) return; ans_bu = bu; memmove(ans, ansbuff, 9 * sizeof(ui)); return; } for (int i = 0; i != 4; ++ i) { ansbuff[deep] = i % 4; dfs(((now + i * a[deep]) | mod) ^ mod, deep + 1, bu + i); } } int main() { freopen("clocks.in", "r", stdin); freopen("clocks.out", "w", stdout); for (int i = 0; i != 9; ++ i) { scanf("%d", &ta); ta = (ta / 3) % 4; tmp = tmp * 8 + ta; } for (int i = 0; i != 9; ++ i) for (int j = 1; j <= plan[i][0]; ++ j) a[i] |= plus_one[plan[i][j]]; dfs(tmp, 0, 0 ); for (int i = 0;i != 9; ++ i) for (int j = 0; j != ans[i]; ++ j) opbuff[++ot] = i + 1; for (int i = 1; i < ot; ++ i) printf("%d ",opbuff[i]); printf("%d\n",opbuff[ot]); return 0; }