第一题(池塘):
题意:
有一个矩阵,'W'代表积水,'.'代表没有积水,如果积水是连起来的就算作一个池塘,一个积水周围8个方向都与它相连。
思路:
这题和之前1月26日的家族很像,就是用深搜去把相连的W去掉并统计池塘个数,模拟赛的时候,因为输入等原因,我才拿了10分,细节很重要~~
代码:
#pragma GCC optimize(2)
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,m,ans;
char c[101][101];
short dx[8]={1,-1,0,0,-1,1,-1,1},
dy[8]={0,0,1,-1,1,1,-1,-1};
void dfs(int x,int y)//搜索
{
if (c[x][y]!='W') return;//如果这里不是积水就退出
c[x][y]='.';//清空
for (int i=0;i<8;i++)//8个方向
if (x+dx[i]>=1&&y+dy[i]>=1&&c[x+dx[i]][y+dy[i]]=='W') dfs(x+dx[i],y+dy[i]);
}
int main()
{
freopen("lkcount.in","r",stdin);
freopen("lkcount.out","w",stdout);
cin>>n>>m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
cin>>c[i][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (c[i][j]=='W') ans++,dfs(i,j);//搜索并统计
cout<<ans;
}
第二题(接苹果):
题意:
有一头牛在2棵苹果树下接苹果,每分钟都有一个苹果从树上掉落,这只牛只愿意走w次,求它在时间t中不超过w步最多能接到多少苹果。
思路:
比赛的时候我不会用动规,所以瞎打了个搜索,结果才40分,这里我用的是记忆化搜索。
代码:
#include<cstdio>
#include<cstring>
int t,w,x[1001],dq,ans,f[1001][301];
int max(int x,int y) {return x>y?x:y;}
int dfs(int dep,int l,int c)//dep代表当前时间,l代表当前位置,c代表当前移动了多少步
{
if (dep>t) return 0;
if (f[dep][c]!=-1) return f[dep][c];//f记录当前时间为dep时移动了c步能接到最多的苹果数量
f[dep][c]=0;
if (l==x[dep]) f[dep][c]=dfs(dep+1,l,c)+1;//如果当前位置等于苹果落下的位置我们就可以让统计一次答案
else
{
f[dep][c]=dfs(dep+1,l,c);//否则我们可以直接往下搜
if (c<w) f[dep][c]=max(dfs(dep+1,x[dep],c+1)+1,f[dep][c]);//如果可以移动,我们就移动到苹果落下的地
} //方
return f[dep][c];
}
int main()
{
freopen("bcatch.in","r",stdin);
freopen("bcatch.out","w",stdout);
scanf("%d%d",&t,&w);
for (int i=1;i<=t;i++)
scanf("%d",&x[i]);
memset(f,-1,sizeof(f));
printf("%d",dfs(1,1,0));
}
第三题(找数):
题意:
在长度为n的序列中找到第k大的数。
思路:
一开始我以为会有重复的,所以用了桶,其实这题很水,数据没有重复的,我们就直接一遍快排过后直接输出第k大的。
代码:
#include<cstdio>
#include<algorithm>
int n,k,a[3000001];
int main()
{
freopen("find.in","r",stdin);
freopen("find.out","w",stdout);
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
std::sort(a+1,a+n+1);//快排
printf("%d",a[n-k+1]);//输出第k大的
}
第四题(最短路线):
题意:
在一个m*n的矩阵中,我们要从左下角走到右上角,求最短路的走法数量。
思路:
一开始我用深搜找到了规律f[i][j]=f[i-1][j]+f[i][j-1],但这个数据很大,我们要用高精加,
这是个很烦的东西。
代码:
#pragma GCC optimize(2)
#include<cstdio>
#include<string>
#include<cstring>
int t,tt,m,n,f[801][801][71],s;
void add()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (i!=1||j!=1)
{
t=1;tt=0;
while (f[i-1][j][t]+f[i][j-1][t]+tt!=0)//高精加
{
f[i][j][t]=f[i-1][j][t]+f[i][j-1][t]+tt;
tt=f[i][j][t]/100000000;
f[i][j][t]%=100000000;
t++;
}
}
}
}
int main()
{
freopen("sline.in","r",stdin);
freopen("sline.out","w",stdout);
scanf("%d%d",&n,&m);
f[1][1][1]=1;
t=2;
add();
for (int i=t-1;i>=1;i--)
{
s=0;
if (i!=t-1)
{
tt=f[n][m][i];
while (tt!=0)
{
tt/=10;
s++;
}
for (int j=1;j<=8-s;j++) printf("0");//压8位
}
printf("%d",f[n][m][i]);
}
}
第五题(棋盘覆盖):
题意:
在一个2^k*2^k的矩阵中,有一个特殊格子,现给出了这个格子的坐标,我们要用L形的纸片把这个矩阵填满,不能叠着,也不能叠到特殊格子,输出填好后的矩阵。
思路:
我们可以用分治算法,将这个矩阵分成几个小的正方形再填。
代码:
#include<cstdio>
int a[1025][1025];
int n,px,py,t;
void dg(int x,int y,int qx,int qy,int c)
{
if(c==1) return;//如果不能分下去了就返回
t++;//t表示填的数字
int s=c/2;//每次分正方形
if(qx>=x+s&&qy>=y+s)
{
a[x+s-1][y+s-1]=t;
a[x+s-1][y+s]=t;
a[x+s][y+s-1]=t;
dg(x,y,x+s-1,y+s-1,s);
dg(x+s,y,x+s,y+s-1,s);
dg(x,y+s,x+s-1,y+s,s);
dg(x+s,y+s,qx,qy,s);
}
if(qx>=x+s&&qy<y+s)
{
a[x+s-1][y+s-1]=t;
a[x+s-1][y+s]=t;
a[x+s][y+s]=t;
dg(x,y,x+s-1,y+s-1,s);
dg(x+s,y,qx,qy,s);
dg(x,y+s,x+s-1,y+s,s);
dg(x+s,y+s,x+s,y+s,s);
}
if(qx<x+s&&qy>=y+s)
{
a[x+s-1][y+s-1]=t;
a[x+s][y+s-1]=t;
a[x+s][y+s]=t;
dg(x,y,x+s-1,y+s-1,s);
dg(x+s,y,x+s,y+s-1,s);
dg(x,y+s,qx,qy,s);
dg(x+s,y+s,x+s,y+s,s);
}
if(qx<x+s&&qy<y+s)
{
a[x+s-1][y+s]=t;
a[x+s][y+s-1]=t;
a[x+s][y+s]=t;
dg(x,y,qx,qy,s);
dg(x+s,y,x+s,y+s-1,s);
dg(x,y+s,x+s-1,y+s,s);
dg(x+s,y+s,x+s,y+s,s);
}
}
int main()
{
freopen("chessboard.in","r",stdin);
freopen("chessboard.out","w",stdout);
scanf("%d",&n);
scanf("%d%d",&px,&py);
dg(1,1,px,py,n);//递归填数
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if (i==px&&j==py) printf("-1 ");
else printf("%d ",a[i][j]);
printf("\n");
}
}