zoukankan      html  css  js  c++  java
  • 【NOI OJ】1816 拨钟问题

    1816:拨钟问题


    总时间限制: 
    1000ms 
    内存限制: 
    65536kB
    描述

    有9个时钟,排成一个3*3的矩阵。

    |-------|    |-------|    |-------|
    |       |    |       |    |   |   |
    |---O   |    |---O   |    |   O   |
    |       |    |       |    |       |
    |-------|    |-------|    |-------|
        A            B            C    
    
    |-------|    |-------|    |-------|
    |       |    |       |    |       |
    |   O   |    |   O   |    |   O   |
    |   |   |    |   |   |    |   |   |
    |-------|    |-------|    |-------|
        D            E            F    
    
    |-------|    |-------|    |-------|
    |       |    |       |    |       |
    |   O   |    |   O---|    |   O   |
    |   |   |    |       |    |   |   |
    |-------|    |-------|    |-------|
        G            H            I    
    (图 1)

    现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。

    移动    影响的时钟
     
     1         ABDE
     2         ABC
     3         BCEF
     4         ADG
     5         BDEFH
     6         CFI
     7         DEGH
     8         GHI
     9         EFHI    
    

    输入
    9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。
    输出
    输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。
    样例输入
    3 3 0 
    2 2 2 
    2 1 2 
    样例输出
    4 5 8 9 
    来源
    1166

    #------------------------------------------------------------------------------#
    openjudge版诈尸~被尘封的openjudge……

    显然,看到此题的标题——枚举,我们都知道要怎么做。
    题目上的“移动”透露了一切,几乎和“移动”有关的,第一就是搜索,第二就是动规。
    这道题我当然选择用枚举——搜索。

    深度优先搜索思路:
    显然一个钟,转4次就相当于没转,所以枚举:转0次,1次,2次和3次,每个钟有9种转法(尽管不是每种都会影响这个种),有九种钟。我们可以用一个常量数组保存。再深搜转的顺序和次数,保存一下即可。

    粗略计算一下深搜时间复杂度:O((4^9)*9*9),才21233664,没有任何毛病。

    代码:
    #include<cstdio>
    #include<cstdlib>
    #define MAXN 9
    int clocks[MAXN+5],ans[MAXN+5];//ans存每个转法转的次数
    const int f[MAXN+5][MAXN+5]=
    {
    	{0},
    	{0,1,1,0,1,1,0,0,0,0},
    	{0,1,1,1,0,0,0,0,0,0},
    	{0,0,1,1,0,1,1,0,0,0},
    	{0,1,0,0,1,0,0,1,0,0},
    	{0,0,1,0,1,1,1,0,1,0},
    	{0,0,0,1,0,0,1,0,0,1},
    	{0,0,0,0,1,1,0,1,1,0},
    	{0,0,0,0,0,0,0,1,1,1},
    	{0,0,0,0,0,1,1,0,1,1},
    };//常量数组,f[i][j]表示第i种转法第j个钟是否转
    int op;
    void read(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    	while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }//读入优化
    bool check()
    {
    	//printf("
    ---------------Check %d---------------
    ",++op);
    	for(int i=1;i<=9;i++)
    	{
    		int t=clocks[i];
    		//printf("i=%d,t=%d
    ",i,t);
    		for(int j=1;j<=9;j++)
    		{
    			t=(t+ans[j]*f[j][i])%4;//计算最后时针的位置
    			//printf("<j=%d,t=%d>",j,t);
    		}//内层枚举转法
    		if(t) return 0;//如果不为0=>没有指向12=>返回false
    	}//外层枚举钟
    	return 1;//之前没有返回=>所有钟都指向12=>返回true
    }
    void print()//输出
    {
    	bool flag=1;//防止多余空格
    	for(int i=1;i<=9;i++)//枚举每种转法
    		for(int j=1;j<=ans[i];j++)//转了几次输出几个
    			if(flag) printf("%d",i),flag=0;
    			else printf(" %d",i);
    }
    void dfs(int x)//枚举转法
    {
    	if(check())
    	{
    		print();
    		exit(0);//exit(0)用于在函数递归中直接结束程序(头文件:cstdlib)
    	}
    	for(int i=0;i<4;i++)//枚举转的次数
    	{
    		ans[x]=i;//保存下来
    		if(x<=9) dfs(x+1);//只要转法符合条件就可以递归(注意是“<=”,因为如果第i次递归有了正确答案,要第i+1次递归才能输出)
    	}
    }
    int main()
    {
    	for(int i=1;i<=9;i++)
    		read(clocks[i]);
    	dfs(1);
    }

    对于上面的“x<=9”,可以这样写:
    void dfs(int x)
    {
    	for(int i=0;i<4;i++)
    	{
    		ans[x]=i;
    	    if(check())
    	    {
    	            print();
    	            exit(0);
    	    }
    		if(x<9) dfs(x+1);
    	}
    }

    这就是dfs的标准格式之一了。

                                                                                                                            By WZY

  • 相关阅读:
    Exchanger
    信号量Semaphore
    CountDownLatch
    Condition
    WCF接口实例介绍
    时间显示
    pymysql-execute
    python之迭代器与生成器
    python之装饰器
    python之函数
  • 原文地址:https://www.cnblogs.com/LinqiongTaoist/p/7203732.html
Copyright © 2011-2022 走看看