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个皇后不放在同一行或同一列或同一斜线上。我们需要求的是可放置的总数。
一直对程序心存疑惑,上一次遍历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
//棋盘问题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;
}