http://train.usaco.org/usacoprob2?a=BI4LEPNXcEa&S=clocks
题目大意:给九个钟的初始状态,指针只可能指向3,6,9,12,有九种操作,每种操作拨动一个固定组合的种顺时针45°,求最少操作能够把所有钟拨到12的情况(操作数相同时,要操作的数字小),按顺序输出
一开始觉得每次有九种选择的可能性,又要输出操作数最少的情况,就想到了用IDDFS,但是在第七个样例超时。为了处理结果操作数比较大的情况,想到了二分,但是然并卵,因为操作数不满足二分性,小的操作数下能够完成并不代表大的操作数必定能够完成
随后迫于无奈使用了BFS,没想到竟然过了,可能因为哈希查重的关系队列并不会变得很长
记录操作我一开始用的string类,但是会超时,就改成了前驱数组。哈希是将钟的情况用一个四进制数表示,直接用数组记录
/*
ID: frontie1
TASK: clocks
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
bool visited[270000];
int pre[270000];
int log[270000];
int table[15];
int oper[10][6] = {{1,2,4,5}, {1,2,3}, {2,3,5,6}, {1,4,7}, {2,4,5,6,8}, {3,6,9}, {4,5,7,8}, {7,8,9}, {5,6,8,9}};
int oper_num[10] = {4, 3, 4, 3, 5, 3, 4, 3, 4};
queue<int> Q;
int encode()
{
int output = 0;
for(int i = 1; i <= 9; ++i){
output <<= 2;
output += table[i];
}
return output;
}
void decode(int num)
{
for(int i = 9; i >= 1; --i){
table[i] = num%4;
num >>= 2;
}
}
void BFS()
{
Q.push(encode());
pre[encode()] = -1;
visited[encode()] = true;
int cur, nxt;
while(!Q.empty()){
cur = Q.front(); Q.pop();
decode(cur);
for(int ope = 0; ope < 9; ++ope){
for(int i = 0; i < oper_num[ope]; ++i){
++table[oper[ope][i]];
table[oper[ope][i]] %= 4;
}
nxt = encode();
if(!visited[nxt]){
visited[nxt] = true;
pre[nxt] = cur;
log[nxt] = ope+1;
if(nxt == 0) return;
Q.push(nxt);
}
for(int i = 0; i < oper_num[ope]; ++i){
table[oper[ope][i]] += 3;
table[oper[ope][i]] %= 4;
}
}
}
}
void print_num(int num)
{
if(pre[num] == -1) return;
print_num(pre[num]);
cout << log[num];
if(num != 0) cout << ' ';
}
int main()
{
freopen("clocks.in", "r", stdin);
freopen("clocks.out", "w", stdout);
for(int i = 1; i <= 9; ++i){
cin >> table[i];
table[i] /= 3;
table[i] %= 4;
}
int ori = encode();
BFS();
print_num(0);
cout << endl;
return 0;
}
附录:IDDFS的做法(会超时的)
/*
ID: frontie1
TASK: clocks
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
bool visited[40][270000];
int table[15];
int oper[10][6] = {{1,2,4,5}, {1,2,3}, {2,3,5,6}, {1,4,7}, {2,4,5,6,8}, {3,6,9}, {4,5,7,8}, {7,8,9}, {5,6,8,9}};
int oper_num[10] = {4, 3, 4, 3, 5, 3, 4, 3, 4};
int step;
int answer[100];
void printtable()
{
for(int i = 1; i <= 9; ++i){
cout << table[i] << ' ';
}
cout << endl;
}
int encode()
{
int output = 0;
for(int i = 1; i <= 9; ++i){
output <<= 2;
output += table[i];
}
return output;
}
bool DFS(int dep, int ope)
{
if(dep == step){
for(int i = 1; i <= 9; ++i){
if(table[i] != 0) return false;
}
return true;
}
for(int i = 0; i < oper_num[ope]; ++i){
++table[oper[ope][i]];
table[oper[ope][i]] %= 4;
}
int code = encode();
if(!visited[step-dep-1][code]){
answer[dep] = ope;
visited[step-dep-1][code] = true;
for(int i = 0; i < 9; ++i){
if(DFS(dep+1, i)) return true;
}
}
for(int i = 0; i < oper_num[ope]; ++i){
table[oper[ope][i]] += 3;
table[oper[ope][i]] %= 4;
}
return false;
}
bool DFS_trigger()
{
for(int i = 0; i < 9; ++i){
if(DFS(0, i)) return true;
}
return false;
}
bool BS(int lo, int hi)
{
if(lo > hi) return false;
int mid = ((lo+hi)>>1);
if(BS(lo, mid-1)) return true;
step = mid;
if(DFS_trigger()) return true;
BS(mid+1, hi);
}
int main()
{
freopen("clocks.in", "r", stdin);
freopen("clocks.out", "w", stdout);
for(int i = 1; i <= 9; ++i){
cin >> table[i];
table[i] /= 3;
table[i] %= 4;
}
// while(!DFS_trigger()){
// ++step;
// }
BS(1, 30);
for(int i = 0; i < step; ++i){
cout << answer[i]+1;
if(i != step-1) cout << ' ';
}
cout << endl;
return 0;
}