今天尝试了一下杭电的题,先看了有关搜索的课件和例题,大概了解了深搜和广搜,不同的空间遍历顺序,比枚举法快捷,常用于路径寻找。
先看了一个有关素数环的例题,从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。
思路是递归填数,依次判断填入的第i个数是否合法,如果一直到20个全部填完,则可以输出该素数环,若不合法,选择下一种可能。
关键代码见下图,判断该填数是否合法,判断是否全部填完,若合法且未填完,则递归填下一个数【search(t+1)】。
然后课件上有一个跳马问题。在5*5格的棋盘上,有一只中国象棋的马,从(1,1)点出发,按日字跳马,它可以朝8个方向跳,但不允许出界或跳到已跳过的格子上,要求在跳遍整个棋盘。这个题和杭电上我准备做的第一题十分相似,所以我将这个题的思路带入了做杭电题的过程中。
杭电的题比这道例题更多要求的地方是:多组输入输出,路径使用字母加数字的方式表示,以及按照字典排序法输出最优结果。(课件例题是要求输出总方案数)
以下为我杭电题的代码:
#include<iostream>
#include<string>
using namespace std;
int u[8]={-2,-2, -1,-1, 1, 1, 2, 2},
v[8]={-1, 1, -2, 2,-2, 2,-1, 1};//八个方向
int a[100][100]={0};
bool b[100][100]={0};
int num=0;//记每一步走在棋盘的哪一格和棋盘的每一格有没有被走过
int search(int,int,int); //以每一格为一个阶段,在每一阶段中试遍8个方向
int print();//展示路径
int p,q;//棋盘大小p*q
int e,f;//e是第几组数据的记录 f是输出数据后跳出用的 f很关键 否则程序很慢
string c;//把坐标转化为字母+数字用的
int main()
{
e=1;
int n;
cin>>n;//多组输入
while(n--)
{
cin>>q>>p;f=0;
a[1][1]=1;b[1][1]=1; //从(1,1)开始走
search(1,1,2); //从(1,1)开始搜索第2步该怎样走
if(num==0) {cout<<"Scenario #"<<e<<":"<<endl;cout<<"impossible"<<endl;e++;}
num=0;
cout<<endl;
}
}
int search(int i,int j,int n)
{
int k,x,y; //定义局部变量
if(n>p*q) {print();f=1;return 0;}//达到最大规模 可以输出该方案
else if(n<=p*q)
{
if(f==1) return 0;
for (k=0;k<=7;k++) //试遍8个方向
{
if(f==1) return 0;
x=i+u[k];y=j+v[k]; //走此方向,得到的新坐标
if(x<=p&&x>=1&&y<=q&&y>=1&&(!b[x][y]))//判断新坐标是否在棋盘上以及这一格之前是否走过
{
b[x][y]=1;
a[x][y]=n;
search(x,y,n+1); //从新坐标(x,y)去搜索下一步该如何走
b[x][y]=0;
a[x][y]=0;
}
}
}
}
int print()
{
if (num<1)
{
num++;//只输出最优(第一个)结果即可
cout<<"Scenario #"<<e<<":"<<endl;
for(int i=1;i<=p*q;i++)//找到第i个到达的点
{
for (int h=1;h<=p;h++)//h和g为第i点的横纵坐标
{
for (int g=1;g<=q;g++)
{
if(a[h][g]==i)
{
c=h+'A'-1;//转化为字母形式
cout<<c<<g;
}
}
}
}
cout<<endl;
e++;
}
}
在经历了三种不同的错误后,这题终于A了……
第一次出现CE,这个头文件不能用啊【#include<bits/stdc++.h>】……
第二次出现WA,输出的那个单词scenario我忘了首字母大写……
第三次出现PE,输出后少了一个回车……
第一次交ACM题…以后记住了…
开始看数论内容,今天只看了一些有关容斥原理的,明天一起写好了。