虽然很多方法都一个意思……但是我因为算错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;
}