USACO 1.4 The Clocks

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


你可能感兴趣的:(USACO 1.4 The Clocks)