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;
}

 

 

posted on 2013-11-29 20:06  小书包_Ray  阅读(240)  评论(0编辑  收藏  举报

导航