NOIP 1997 提高组 复赛 棋盘问题

来源:互联网 发布:网络审核员工作 编辑:程序博客网 时间:2024/05/27 20:55

NOIP 1997 提高组 复赛 棋盘问题

1.题目看懂了,但没有什么想法。

http://blog.csdn.net/duofg/article/details/181761

http://bbs.csdn.net/topics/380237509

http://ceeji.net/blog/noip-1997/

2.研究http://blog.csdn.NET/duofg/article/details/181761发现涉及 回溯 算法。好吧,开始学习回溯算法。

3.学习回溯算法思路:希望能找到回溯算法,最简单的例子,有输入,输出,并且代码量极短,这样能帮助迅速掌握回溯算法,开始搜索。

4.找到一篇:http://www.cnblogs.com/Creator/archive/2011/05/20/2052341.html开始学习:

经典的N后问题

问题描述:在n*n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规矩,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n*n格的棋盘上方置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。我们需要求的是可放置的总数。

http://images.cnblogs.com/cnblogs_com/Creator/201105/201105202123211208.png

一直对程序心存疑惑,上一次遍历x[t]的值是否会对下一次有影响,因为x[t]是全局变量,跟踪程序后,发现没影响,后来再想想,明白了,x[t]一次只能赋一次值,故上一次对下一次的值无影响,因为一行只能放一枚棋子。

按照自己的理解,进行编码,程序如下:

//nh2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int n;
int sum;
int x[100];
int place(int t){
    int j;
    for(j=1;j<t;j++)
        if(x[j]==x[t]||abs(t-j)==abs(x[t]-x[j]))
            return 0;
    return 1;
}
void dfs(int t){
    int j;
    if(t>n){
        sum++;
    }else{
        for(j=1;j<=n;j++){
            x[t]=j;
            if(place(t))
                dfs(t+1);
        }
    }
}
int main(){
    while(scanf("%d",&n)!=EOF){
        sum=0;
        memset(x,0,sizeof(x));
        dfs(1);
        printf("%d\n",sum);   
    }
    return 0;
}

5.学习了《啊哈!算法》深度优先遍历,感觉水平又有了提高,编码,提交,60分,算是基本掌握,数据点4,WA,数据点5,TLE,终于可以开始尝试看他人本题代码了。

6.本人算法两个问题,一是解决了第一行之和为最小、但没解决第一列之和为最小;还有一个算法时间复杂度过大。

2017-1-11 21:54

7.原本打算对http://ceeji.net/blog/noip-1997/进行分析,pascal提交,0分,那么只好作罢。

8.http://blog.csdn.net/duofg/article/details/181761稍作修改,提交即可得80分,原因是测试结果又多种满足条件的解。程序相当棒,一般的程序到n=5就完了,程序到n=8还是秒杀,当然到n=9也完了。值得好好研究。

9.本人,认为此题最难就是如何判断加入数据正确,并且运算量较小;如何确定第一列最小。研究成果如下,

10.http://wenku.baidu.com/view/463f3d6527d3240c8447ef4e.html值得一读。

附上AC代码,编译环境Dev-C++4.9.9.2


附上40分代码,编译环境Dev-C++4.9.9.2

//棋盘问题3  骗分代码,估计能骗20分 实得40分,真是太高兴了
#include <stdio.h>

int main(){
    printf("NO\n");
}


附上60分代码,编译环境Dev-C++4.9.9.2

//1997 提高组 复赛 棋盘问题
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int n;
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//右下左上
int a[20][20],visited[20][20];
int v_b[100+10];
void print(int n){
    int i,j;
    for(i=1;i<=n;i++){
        printf("%d",a[i][1]);
        for(j=2;j<=n;j++)
            printf(" %d",a[i][j]);
        printf("\n");
    }
}
int isPrime(int a){
    int i;
    if(a==1)
        return 0;
    if(a==2)
        return 1;
    if(a%2==0)
        return 0;
    for(i=3;i*i<=a;i+=2)
        if(a%i==0)
            return 0;
    if(i*i>a)
        return 1;
}
void dfs(int r,int c,int step){
    int i,j,k;
    int next_r,next_c;
    int j_r,j_c;
    int flag;
    if(step==n*n){
        print(n);
        exit(0) ;
    }
    for(i=0;i<4;i++){
        next_r=r+next[i][0];
        next_c=c+next[i][1];
        if(next_r>0&&next_r<=n&&next_c>0&&next_c<=n&&visited[next_r][next_c]==0){
            for(j=1;j<=n*n;j++)
                if(v_b[j]==0){
                    if(isPrime(a[r][c]+j)){
                        //printf("%d %d %d %d\n",r,c,a[r][c],j);
                        flag=1;
                        for(k=0;k<4;k++){//四周是否和还是质数
                            j_r=next_r+next[k][0];
                            j_c=next_c+next[k][1];
                            if(a[j_r][j_c]>0){
                                if(isPrime(a[j_r][j_c]+j))
                                    flag*=1;
                                else
                                    flag*=0;
                            }else{
                                flag*=1;
                            }
                        }
                        if(flag==1){
                            v_b[j]=1;
                            visited[next_r][next_c]=1;
                            a[next_r][next_c]=j;
                            dfs(next_r,next_c,step+1);
                            a[next_r][next_c]=0;
                            visited[next_r][next_c]=0;
                            v_b[j]=0;
                        }    
                        
                    }
                }                
        }
    }
}

int main(){
    memset(a,0,sizeof(a));
    memset(visited,0,sizeof(visited));
    memset(v_b,0,sizeof(v_b));
    scanf("%d",&n);
    if(n==1){
        printf("NO\n");
        return 0;
    }
    a[1][1]=1;
    visited[1][1]=1;
    v_b[1]=1;
    dfs(1,1,1);
    printf("NO\n");
    return 0;
}


0 0