jzoj_2月3日D组

第一题(池塘)

题意:

    有一个矩阵,'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"); 
	}
}






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值