http://ace.delos.com/usacoprob2?S=clocks&a=3hMw0XdJ4KO

枚举暴力搜索法

虽然为暴利搜索,不过结合题目的特点还是需要注意一些技巧的,注意该题目的特点:

1每种变换方法可以使用0~3次,因为如果使用4的话,正好转一圈,和0等效。

2并且每种变换方法在前与在后是等效的。所以根据题目输出要求,最小字典序。

该法枚举每条路径,枚举的顺序很重要,因为找到最小的就停止搜索了,所以控制好枚举顺序有些技巧。

根据排列组合基础可以知道,该问题的每种path路径为 1,2,3,4,5,6,7,8,9,11,12,13,。。。。998,999,1112,1113,1114.。。。

注意,999之后按照正常字典序的话应该是1111,但是正确的应该是1112,这个很关键,否则会出现组合爆炸情形的,因为如果直接按照字典序搜索的话,需要的总搜索次数为:

因为每种数字在path路径中最多出现3次,所以path的最长长度为27,一共就有9^27种,这个数据量是肯定会超时的!!!

但是如果加一个相同数字不能超过3次的限制之后,总的搜索次数就会大大下降,一共是4^9 = 262144 个,少了好多,可以暴力搜索了。。。

在这个“局限字典序”的生成上用的递归DFS。。。

 

/*
ID:liuweiv2
PROG:clocks
LANG:C++
*/
#include<iostream>
using namespace std;
#include<fstream>


int orig[3][3];
int temp[3][3];
char moves[10][6] = {"","ABDE","ABC","BCEF","ADG","BDEFH","CFI","DEGH","GHI","EFHI"};
int path[28];
int count[28];
ifstream infile;
ofstream outfile;


void copy(){
    for(int i=0;i<3;i++)
        for(int j = 0;j<3;j++)
            temp[i][j] = orig[i][j];
}

bool perChange(char c,bool isAdd){
    if(c == '\0')
        return false;

    int p ;
    if(isAdd)
        p  = 3;
    else
        p  = -3;
    int t = c - 'A';
    int i = t/3;
    int j = t%3;
    temp[i][j]+=p;
    if(temp[i][j] == 15)
        temp[i][j] = 3;
    if(temp[i][j] == 0)
        temp[i][j] = 12;

    return true;
}

void change(int moveNum,bool isAdd){
    for(int i=0;i<6;i++)
        if(perChange(moves[moveNum][i],isAdd) == false)
            break;
}

void print(){
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++)
            cout<<temp[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;
}

bool check(){
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            if(temp[i][j]!=12)
                return false;
    return true;
}


bool isFind = false;

void dfs(int step,int max){
    if(isFind)
        return;

    if(step>max){

        //到达叶子节点,检查
        copy();
        for(int i=1;i<step;i++)
            change(path[i],true);
        if(check()){

            isFind = true;
            outfile<<path[1];
            for(int i=2;i<step;i++)
                outfile<<" "<<path[i];
            outfile<<endl;

        }
        return ;
    }


    int i;
    if(step == 1)
        i  = 1;
    else
        i = path[step-1];

    for(;i<=9;i++){
        if(isFind)
            return;

        path[step] = i;
        count[i]++;

        if(count[i] == 4){
            count[i]--;
            continue;
        }

        dfs(step+1,max);

        count[i]--;

    }

    return;
}
int main(){
    

    infile.open("clocks.in");
    outfile.open("clocks.out");
    //memset(count,0,sizeof(count));

    for(int i=0;i<3;i++)
        for(int j = 0;j<3;j++)
            infile>>orig[i][j];

    for(int i=1;i<=27;i++){
        if(isFind)
            break;
        dfs(1,i);
    }

    
    
    return 0;
}

            

 Executing...
   Test 1: TEST OK [0.000 secs, 3344 KB]
   Test 2: TEST OK [0.000 secs, 3344 KB]
   Test 3: TEST OK [0.022 secs, 3344 KB]
   Test 4: TEST OK [0.032 secs, 3344 KB]
   Test 5: TEST OK [0.022 secs, 3344 KB]
   Test 6: TEST OK [0.119 secs, 3344 KB]
   Test 7: TEST OK [0.119 secs, 3344 KB]
   Test 8: TEST OK [0.162 secs, 3344 KB]
   Test 9: TEST OK [0.119 secs, 3344 KB]

All tests OK.

由于在操作上没有进行优化,直接进行的最直接的模拟,所以耗时还是比较严重的!抽空用“位加速”修改一下 !!!

 

posted on 2012-05-16 00:49  geeker  阅读(317)  评论(0编辑  收藏  举报