USACO SEC.1.4 No.2 The Clocks ★经典题目
题意:详细见USACO描述
解法:
作为IOI真题,这道题目确实是非常经典,有许多方法可以求解。
基本算法:最容易想到的就是
枚举所有情况(4^9复杂度)在时间复杂度上是可以接受的
DFS与上面的方法类似
BFS,与DFS不同之处在于,由于题目要求找到最短且字典序最小的解,所以BFS一旦搜到答案可以立即返回
BFS需要解决的问题:
1.如何表征当前状态,常规的作法仍然是数组。string也可以,但时间C++的string时间复杂度太大。
2.如何进行状态的比较和复制,如果采用数组的话,可以直接使用memcmp速度更快,同理memcpy
3.队列,采用STL的queue
4.Hash判重,BFS中关键的一步,一开始想用STL的set,但状态表示起来更为复杂,所以单独用数组作一个
hash table,注意要能够完全覆盖所有状态,空间不够大的话,不能够第一时间找到答案。如何实现高效的
hash是本题目的一个核心问题,解决了这个问题,题目就解决了一大半了
BFS求解:
/* ID: lsswxr1 PROG: clocks LANG: C++ */ #include <iostream> #include <vector> #include <map> #include <list> #include <set> #include <deque> #include <stack> #include <queue> #include <algorithm> #include <cmath> #include <cctype> #include <cstdio> #include <iomanip> #include <cmath> #include <cstdio> #include <string> #include <cstring> #include <fstream> using namespace std; ///宏定义 const int INF = 1000000000; const int MAXN = 15; const int maxn = MAXN; ///全局变量 和 函数 #define USACO #ifdef USACO #define cin fin #define cout fout #endif ////////////////////////////////////////////////////////////////////////// int move[9][5] = { {0,1,3,4},{0,1,2},{1,2,4,5},{0,3,6}, {1,3,4,5,7},{2,5,8},{3,4,6,7},{6,7,8},{4,5,7,8} }; int Nmove[9] = {4,3,4,3,5,3,4,3,4}; //每种方案对应需要操作的个数 typedef int state[9]; typedef int cmtM[9]; int value[10]; const int HashSize = 300007; inline bool isGoal(state a) { for(int i = 0; i < 9; i++) if(a[i]) return false; return true; } void doOper(state &a,int op) //采用第op种方案对于状态a进行操作 { for(int i = 0; i < Nmove[op]; i++) ++a[move[op][i]] %= 4; } struct node { state curState; cmtM cnt; }; int hash(const state& s) { int t = 0; for(int i = 9; i >= 0; i--) t += value[9 - i] * s[i]; return t % HashSize; } state startStat; queue<node> que; bool hashTable[HashSize]; int main() { #ifdef USACO ofstream fout ("clocks.out"); ifstream fin ("clocks.in"); #endif ///变量定义 for(int i = 0; i < 9; i++) { int t; cin >> t; startStat[i] = t / 3 % 4; } value[0] = 1; for(int i = 1; i < 10; i++) value[i] = value[i-1] * 4; while (!que.empty()) que.pop(); memset(hashTable, 0, sizeof(hashTable)); node theNode; memcpy(theNode.curState, startStat, sizeof(theNode.curState)); memset(theNode.cnt, 0, sizeof(theNode.cnt)); que.push(theNode); while (!que.empty()) { theNode = que.front(); que.pop(); if (isGoal(theNode.curState)) { break; } for (int i = 0; i < 9; i++) { node tmp; memcpy(tmp.curState, theNode.curState, sizeof(tmp.curState)); memcpy(tmp.cnt, theNode.cnt, sizeof(tmp.cnt)); if (tmp.cnt[i] + 1 >= 4) continue; tmp.cnt[i] += 1; doOper(tmp.curState, i); int u = hash(tmp.curState); if (!hashTable[u]) { hashTable[u] = true; que.push(tmp); } } } bool flag = true; for (int i = 0; i < 9; i++) { while (theNode.cnt[i] != 0) { if(flag) { cout << i + 1; flag = false; } else cout << " " << i + 1; theNode.cnt[i]--; } } cout << endl; ///结束 return 0; }