USACO Magic Squares 解题报告

在发现8!=40320之后,我发现空间不是影响因素了。只要不重复运算,时间和空间都是足够的。

值得借鉴的地方:

1.对于转换的处理:

/* the set of transformations, in order */

static int tforms[3][8] = { {8, 7, 6, 5, 4, 3, 2, 1}, {4, 1, 2, 3, 6, 7, 8, 5}, 

{1, 7, 2, 4, 5, 3, 6, 8} };

这里是另外一种思路,处理起来相对更简单些。思路是直接将转化理解为对不同拷贝位置(初始位置转换后的位置)的映射。比如第一个转化里面第0为应该拷贝第7位(8-1)。第一个转化其实就是这一个数组,即拷贝位置的映射。

2.康拓展开

康拓展开是个好定理:作用是求一个排列如45213在这个5个数的全排列中的序列。可以直接移步这里:http://blog.csdn.net/fairyroad/article/details/7555773

代码写得很好。

/*
ID: thestor1
LANG: C++
TASK: msquare
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <algorithm>
#include <stack>
#include <set>

using namespace std;

const int size = 8;
const int MAX = 40320;

//8! = 40320
struct Square{
	int h;
	int square[size];
	char op;
	int prev;

	Square()
	{
		h = -1;
	}

	int hash()
	{
		if(h > 0)
		{
			return h;
		}
		int h = 0;
		for(int i = 0; i < size; ++i)
		{
			h = (h << 3) + square[i];
		}
		return h;
	}
};

Square squares[MAX];

bool equal(Square &s1, Square &s2)
{
	return s1.hash() == s2.hash();
}

bool equal(int *s1, int *s2)
{
	for(int i = 0; i < size; ++i)
	{
		if(s1[i] != s2[i])
		{
			return false;
		}
	}
	return true;
}

void copy(int *s, int *d)
{
	for(int i = 0; i < size; ++i)
	{
		d[i] = s[i];
	}
}

void A(int *square)
{
	for(int i = 0; i <= 3; ++i)
	{
		int tmp = square[i];
		square[i] = square[7 - i];
		square[7 - i] = tmp;
	}
}

void B(int *square)
{
	int tmp = square[3];
	for(int i = 3; i >= 1; --i)
	{
		square[i] = square[i - 1];
	}
	square[0] = tmp;

	tmp = square[4];
	for(int i = 4; i <= 6; ++i)
	{
		square[i] = square[i + 1];
	}
	square[7] = tmp;
}

void C(int *square)
{
	int tmp = square[1];
	square[1] = square[6];
	square[6] = square[5];
	square[5] = square[2];
	square[2] = tmp;
}

int main()
{
	FILE *fin  = fopen ("msquare.in", "r");
	FILE *fout = fopen ("msquare.out", "w");
	//freopen("log.txt", "w", stdout);

	Square targetSq;
	//int target[size];
	for(int i = 0; i < size; ++i)
	{
		fscanf(fin, "%d", &targetSq.square[i]);
	}

	set<int> sqs;
	int top = 0;
	for(int i = 0; i < size; ++i)
	{
		squares[top].square[i] = i + 1;
	}
	sqs.insert(squares[top].hash());
	top++;

	int final = -1;
	for(int i = 0; i < top; ++i)
	{
		//fprintf(stdout, "i: %d, top: %d\n", i, top);
		Square sq = squares[i];
		if(equal(sq, targetSq))
		{
			final = i;
			break;
		}

		copy(sq.square, squares[top].square);
		A(squares[top].square);
		if(sqs.find(squares[top].hash()) == sqs.end())
		{
			squares[top].prev = i;
			squares[top].op = 'A';
			sqs.insert(squares[top].hash());
			top++;
		}

		copy(sq.square, squares[top].square);
		B(squares[top].square);
		if(sqs.find(squares[top].hash()) == sqs.end())
		{
			squares[top].prev = i;
			squares[top].op = 'B';
			sqs.insert(squares[top].hash());
			top++;
		}

		copy(sq.square, squares[top].square);
		C(squares[top].square);
		if(sqs.find(squares[top].hash()) == sqs.end())
		{
			squares[top].prev = i;
			squares[top].op = 'C';
			sqs.insert(squares[top].hash());
			top++;
		}
	}

	stack<char> seq;
	while(final != 0)
	{
		seq.push(squares[final].op);
		final = squares[final].prev;
	}
	fprintf(fout, "%d\n", seq.size());
	while(!seq.empty())
	{
		fprintf(fout, "%c", seq.top());
		seq.pop();
	}
	fprintf(fout, "\n");

	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值