本周学bfs广度优先搜索,当题目求最短路径,最小步数等最优解问题时,优先使用bfs,因为一找到答案就可以停止搜索了;
P1135 奇怪的电梯
1.思路:非常普通的一道训练dfs的模板题。
2.代码:
#include <bits/stdc++.h>
using namespace std;
int vis[205];
int ss[2]={1,-1};
int ans[205];
int k[205];
queue<int> q;
int main()
{
int n,a,b;
cin>>n>>a>>b;
memset(vis,-1,sizeof(vis));
for(int i=1;i<=n;i=i+1)
{
cin>>k[i];
}
vis[a]=0;
q.push(a);
while(!q.empty())
{
int zx=q.front();
q.pop();
for(int i=0;i<2;i=i+1)
{
int nx=zx+ss[i]*k[zx];
if(nx<=n&&nx>=1&&vis[nx]==-1)
{
vis[nx]=vis[zx]+1;
if(nx==b)
{
break;
}
q.push(nx);
}
}
}
cout<<vis[b];
}
P1443 马的遍历
1.思路:也是一道非常easy的模板题,但因为我们需要同时储存x,y这两个坐标点,所以创建队列时queue <pair<int,int> >p,用q.push(make_pair(x,y))来将点的信息存入队列中
2.代码:
P3958 [NOIP2017 提高组] 奶酪
1.思路:感觉思路很简单,但不管怎么改都只有80分,很崩溃,先放个80分代码。(三天后:这题是真恶心啊,好吧是我太废物了,两个相乘会爆掉,需要将其转为long long)
2.代码:
#include <bits/stdc++.h>
using namespace std;
long long x[1005],y[1005],z[1005];
int vis[1005];
int d[1005][1005];
long long dist(int x1,int y1,int z1,int x2,int y2,int z2)
{
return (long long)(x1-x2)*(x1-x2)+(long long)(y1-y2)*(y1-y2)+(long long)(z1-z2)*(z1-z2);
}
queue<int>q;
int main()
{
int t;
cin>>t;
for(int k=1;k<=t;k=k+1)
{
while(!q.empty())
{
q.pop();
}
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(d));
int ff=0;
long long n,h,r;
cin>>n>>h>>r;
for(int i=1;i<=n;i=i+1)
{
cin>>x[i]>>y[i]>>z[i];
if(abs(z[i])<=r)
{
vis[i]=1;
q.push(i);
}
}
for(int i=1;i<=n;i=i+1)
{
for(int j=i+1;j<=n;j=j+1)
{
if(dist(x[i],y[i],z[i],x[j],y[j],z[j])<=2*2*r*r)
{
d[i][j]=1;
d[j][i]=1;
}
}
}
while(!q.empty())
{
int zx=q.front();
if(abs(h-z[zx])<=r)
{
ff=1;
cout<<"Yes"<<endl;
break;
}
q.pop();
for(int i=1;i<=n;i=i+1)
{
if(d[zx][i]==1&&vis[i]==0)
{
vis[i]=1;
q.push(i);
}
}
}
if(ff==0)
{
cout<<"No"<<endl;
}
}
}
P1162 填涂颜色
1.思路:这道题是搜索里找连通块的题目,用深搜找而且不用回溯
2.代码:
P3956 [NOIP2017 普及组] 棋盘
1.思路:这道题很容易就超时了,所以我们需要进行适当的剪枝,才能够通过题目。我们可以开个d数组记录到达i,j的最小花费,每次搜索前判断花费是否小于d,否则不搜(记忆化剪枝);还可以开个vis数组来记录i,j是否走过,如果走过就不搜(最普通的剪枝)
2.代码:
#include <bits/stdc++.h>
using namespace std;
int a[105][105];
int sx[4]={-1,0,1,0};
int sy[4]={0,1,0,-1};
int vis[105][105];
int d[105][105];
int ans=0x3f3f3f3f;
int hf;
int n,m;
int f=-1;
void dfs(int x,int y,int z)
{
if(x==m&&y==m)
{
if(hf<ans)
{
f=1;
ans=hf;
}
return;
}
else
{
for(int i=0;i<4;i=i+1)
{
int nx=x+sx[i];
int ny=y+sy[i];
if(vis[nx][ny]==0&&nx>=1&&nx<=m&&ny>=1&&ny<=m)
{
if(a[nx][ny]!=-1)
{
if(a[nx][ny]==a[x][y])
{
vis[nx][ny]=1;
d[nx][ny]=hf;
dfs(nx,ny,0);
vis[nx][ny]=0;
}
else
{
if(hf+1<d[nx][ny])
{
hf=hf+1;
d[nx][ny]=hf;
vis[nx][ny]=1;
dfs(nx,ny,0);
vis[nx][ny]=0;
hf=hf-1;
}
}
}
else
{
if(z==0)
{
if(hf+2<d[nx][ny])
{
hf=hf+2;
a[nx][ny]=a[x][y];
vis[nx][ny]=1;
d[nx][ny]=hf;
dfs(nx,ny,1);
hf=hf-2;
vis[nx][ny]=0;
a[nx][ny]=-1;
}
}
}
}
}
}
}
int main()
{
memset(a,-1,sizeof(a));
memset(d,0x3f3f3f3f,sizeof(d));
cin>>m>>n;
for(int i=1;i<=n;i=i+1)
{
int x,y,c;
cin>>x>>y>>c;
a[x][y]=c;
}
vis[1][1]=1;
dfs(1,1,0);
if(f==-1)
{
cout<<f<<endl;
}
else
{
cout<<ans<<endl;
}
}
P1126 机器人搬重物
1.思路:这道题用广搜是最合适的,因为咱们找到最小的答案就可以退出了,而dfs我们很可能会因为搜索次数过多而被时间限制(剪枝了也很可能没用)。另外,坐标点在网格线上移动,所以我们需要对输入进行优化,而且状态的分类也很复杂,一共有4乘以3=12种状态。
2.代码:
#include <bits/stdc++.h>
using namespace std;
int a[55][55];
int vis[55][55][5];
int xyb[3]={1,2,3};
int fx[4]={1,2,3,4};
int qx,qy,zx,zy;
int ans=0x3f3f3f3f;
int sj=0;
int d[55][55][5];
int n,m;
int fff=-1;
void dfs(int x,int y,int z)
{
if(x==zx&&y==zy)
{
fff=1;
ans=min(ans,sj);
}
else
{
for(int i=0;i<4;i=i+1)
{
int nz=fx[i];
int nx,ny;
if(nz==1)
{
for(int j=0;j<3;j=j+1)
{
int nx=x;
int ny=y+xyb[j];
if(nx>=1&&nx<=n-1&&ny>=1&&ny<=m-1&&vis[nx][ny][nz]==0)
{
int f=1;
for(int k=xyb[j]-1;k>=0;k=k-1)
{
if(a[nx][ny-k]==1)
{
f=0;
break;
}
}
if(f==0)
{
break;
}
if(f==1)
{
int ff=0;
if(abs(z-nz)==2)
{
ff=1;
}
else if(z==nz)
{
ff=2;
}
if(ff==1&&sj+3<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+3;
sj=sj+3;
dfs(nx,ny,nz);
sj=sj-3;
vis[nx][ny][nz]=0;
}
else if(ff==0&&sj+2<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+2;
sj=sj+2;
dfs(nx,ny,nz);
sj=sj-2;
vis[nx][ny][nz]=0;
}
else if(ff==2&&sj+1<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+1;
sj=sj+1;
dfs(nx,ny,nz);
sj=sj-1;
vis[nx][ny][nz]=0;
}
}
}
}
}
if(nz==2)
{
for(int j=0;j<3;j=j+1)
{
int nx=x+xyb[j];
int ny=y;
if(nx>=1&&nx<=n-1&&ny>=1&&ny<=m-1&&vis[nx][ny][nz]==0)
{
int f=1;
for(int k=xyb[j]-1;k>=0;k=k-1)
{
if(a[nx-k][ny]==1)
{
f=0;
break;
}
}
if(f==0)
{
break;
}
if(f==1)
{
int ff=0;
if(abs(z-nz)==2)
{
ff=1;
}
else if(z==nz)
{
ff=2;
}
if(ff==1&&sj+3<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+3;
sj=sj+3;
dfs(nx,ny,nz);
sj=sj-3;
vis[nx][ny][nz]=0;
}
else if(ff==0&&sj+2<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+2;
sj=sj+2;
dfs(nx,ny,nz);
sj=sj-2;
vis[nx][ny][nz]=0;
}
else if(ff==2&&sj+1<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+1;
sj=sj+1;
dfs(nx,ny,nz);
sj=sj-1;
vis[nx][ny][nz]=0;
}
}
}
}
}
if(nz==3)
{
for(int j=0;j<3;j=j+1)
{
int nx=x;
int ny=y-xyb[j];
if(nx>=1&&nx<=n-1&&ny>=1&&ny<=m-1&&vis[nx][ny][nz]==0)
{
int f=1;
for(int k=0;k<xyb[j];k=k+1)
{
if(a[nx][ny+k]==1)
{
f=0;
break;
}
}
if(f==0)
{
break;
}
if(f==1)
{
int ff=0;
if(abs(z-nz)==2)
{
ff=1;
}
else if(z==nz)
{
ff=2;
}
if(ff==1&&sj+3<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+3;
sj=sj+3;
dfs(nx,ny,nz);
sj=sj-3;
vis[nx][ny][nz]=0;
}
else if(ff==0&&sj+2<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+2;
sj=sj+2;
dfs(nx,ny,nz);
sj=sj-2;
vis[nx][ny][nz]=0;
}
else if(ff==2&&sj+1<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+1;
sj=sj+1;
dfs(nx,ny,nz);
sj=sj-1;
vis[nx][ny][nz]=0;
}
}
}
}
}
if(nz==4)
{
for(int j=0;j<3;j=j+1)
{
int nx=x-xyb[j];
int ny=y;
if(nx>=1&&nx<=n-1&&ny>=1&&ny<=m-1&&vis[nx][ny][nz]==0)
{
int f=1;
for(int k=0;k<xyb[j];k=k+1)
{
if(a[nx+k][ny]==1)
{
f=0;
break;
}
}
if(f==0)
{
break;
}
if(f==1)
{
int ff=0;
if(abs(z-nz)==2)
{
ff=1;
}
else if(z==nz)
{
ff=2;
}
if(ff==1&&sj+3<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+3;
sj=sj+3;
dfs(nx,ny,nz);
sj=sj-3;
vis[nx][ny][nz]=0;
}
else if(ff==0&&sj+2<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+2;
sj=sj+2;
dfs(nx,ny,nz);
sj=sj-2;
vis[nx][ny][nz]=0;
}
else if(ff==2&&sj+1<d[nx][ny][nz])
{
vis[nx][ny][nz]=1;
d[nx][ny][nz]=sj+1;
sj=sj+1;
dfs(nx,ny,nz);
sj=sj-1;
vis[nx][ny][nz]=0;
}
}
}
}
}
}
}
}
int main()
{
memset(d,0x3f3f3f3f,sizeof(d));
cin>>n>>m;
int ffff=0;
for(int i=1;i<=n;i=i+1)
{
for(int j=1;j<=m;j=j+1)
{
int x;
cin>>x;
if(x==1)
{
ffff=1;
a[i][j]=1;
a[i-1][j]=1;
a[i][j-1]=1;
a[i-1][j-1]=1;
}
}
}
cin>>qx>>qy>>zx>>zy;
char c;
int z;
cin>>c;
if(c=='E')
{
z=1;
}
if(c=='S')
{
z=2;
}
if(c=='W')
{
z=3;
}
if(c=='N')
{
z=4;
}
vis[qx][qy][z]=1;
if(ffff==0)
{
cout<<32;
}
else
{
dfs(qx,qy,z);
}
if(fff==1&&ffff==1)
{
cout<<ans<<endl;
}
else if(fff==-1&&ffff==1)
{
cout<<-1;
}
}
7-3 小源爱写题
小源现在想要加训。
他准备写 n 道题目来提高自己的算法能力。
他决定分天数(至少 2 天)完成这 n 道题目,并且每天都需要写正整数道题目。
为了提高训练效果,他规定每天写的题目数必须比上一天写的多。
输入格式:
一行一个整数,代表 n(5≤n≤500) 。
输出格式:
一个整数表示小源写完这 n 道题的所有可能方案数。
输入样例:
212
输出样例:
在这里给出相应的输出。例如:995645335
1.思路:这是一道动态规划题(好难)。我们定义状态“天数/当前总共完成的题数/前一天完成的题数”,我们可以发现天数在这道题中并不会影响总方案数(因为我们定义了状态:前一天的做题量)。另外我们求的转移方程是f[i][j]+=f[i-j][k],其中的k表示在做i-j道题时,前一天的做题数,虽然k不是我们定义的状态,但缺少了k就缺少了关键信息,所以必须有k这一层循环。
2.代码:
#include <bits/stdc++.h>
using namespace std;
long long f[505][505];
long long ans;
int main()
{
int n;
cin>>n;
f[0][0]=1;
for(int i=1;i<=n;i=i+1)
{
for(int j=1;j<=i;j=j+1)
{
for(int k=0;k<j;k=k+1)
{
f[i][j]=f[i][j]+f[i-j][k];
}
}
}
for(int j=0;j<=n;j=j+1)
{
ans=ans+f[n][j];
}
cout<<ans-1;
}