2021寒假——洛谷刷题计划(15题)

P2327 扫雷(DFS递归)

递归就可以分类讨论了!

#include 
int arr1[10001],arr2[10001];
int n,ans;
int check(int x){
	if(arr1[x-1]+arr1[x]+arr1[x+1]==arr2[x])
	//判断当前情况下是否满足arr2数组 
		return 1;
	return 0;
}
void dfs(int k){
	if(k==n+1){
	//搜索结束条件,如果直到最后一个判断都符合条件,说明方案可行 
		if(check(n))
			ans++;
		return;
	}
	arr1[k]=1;
	if(k==1||check(k-1))
	//假设该格子有雷,且判断无误,继续搜下一个格子
	//必须check(k-1),因为如果check(k),该格子下方还不确定是否有雷,画个图就懂了 
		dfs(k+1);
	arr1[k]=0;
	if(k==1||check(k-1))
	//假设该格子无雷,且判断无误,继续搜下一个格子 
		dfs(k+1);
	return;
}
int main(){
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&arr2[i]);
		//arr2数组的第一个位置是空着的 
	dfs(1);
	//所以dfs从第二个位置开始搜索 
	printf("%d",ans);
	return 0;
}

P1002 过河卒(详细dp)

方法一:DFS,参考了以前需要回溯的那道题,不过时间复杂度太大,得了40分

#include 
int Bx,By,Mx,My;
long long ans; 
const int d[8][2]={-2,-1,-1,-2,1,-2,2,-1,2,1,1,2,-1,2,-2,1};
void DFS(int x,int y){
	int i;
	if(x==Bx+1||y==By+1) return;
	for(i=0;i<8;i++)
		if(x+d[i][0]==Mx&&y+d[i][1]==My) return;
	if(x==Mx&&y==My) return;
	if(x==Bx&&y==By){
		ans++;
		return;
	}
	DFS(x+1,y);
	DFS(x,y+1);
	return;
}
int main(){
	scanf("%d%d%d%d",&Bx,&By,&Mx,&My);
	DFS(0,0);
	printf("%lld",ans);
	return 0;
}

方法二:dp,但是c编译器第三组数据莫名其妙结果为0,但cpp正常,可参考:

#include  
const int fx[]={0,-2,-1,1,2,2,1,-1,-2};
const int fy[]={0,1,2,2,1,-1,-2,-2, -1};
//马可以走到的位置
int bx,by,mx,my;
int i,j;
unsigned long long f[40][40];
//f[i][j]代表从A点到(i,j)会经过的线路数
int s[40][40];
//判断这个点有没有马盯着
int max(int a,int b){
	if(a>=b) return a;
	else return b;
}
int main(){
    scanf("%d%d%d%d",&bx,&by,&mx,&my);
    bx+=2;by+=2;mx+=2;my+=2;
    //坐标+2以防越界
    f[2][2]=1;
	//初始化
    s[mx][my]=1;
	//标记马的位置
    for(i=1;i<=8;i++)
        s[mx+fx[i]][my+fy[i]]=1;
    for(i=2;i<=bx;i++){
        for(j=2;j<=by;j++){
            if(s[i][j])continue;
            f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]); 
            //状态转移方程
        }
    }
    printf("%llu",f[bx][by]);
    return 0;
}

方法三:比用max好理解的dp,适合参考:

#include  
int b[30][30];
//用于标记 
long long a[30][30];
//用于记录走到某一个格子共有多少种路线 
int dx[8]={2,1,-1,-2,-2,-1,1,2};
int dy[8]={1,2,2,1,-1,-2,-2,-1};
int n,m,x,y;
int main(){
	int i,j;
	scanf("%d%d%d%d",&n,&m,&x,&y);
	b[x][y]=1;
	for(i=0;i<=7;i++){
		//标记马和马挡道的位置 
		 if(x+dx[i]>=0&&x+dx[i]<=n&&y+dy[i]>=0&&y+dy[i]<=m){
		 	b[x+dx[i]][y+dy[i]]=1;
		 }
	}
	int k=0;
	while(!b[k][0]&&k<=n){
	//最左一列,到达的方式只可能有一种,学 
		a[k++][0]=1;
	}
	int l=0;
	while(!b[0][l]&&l<=m){
	//最上一列,到达的方式只可能有一种,学 
		a[0][l++]=1;
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			if(b[i][j]){
				a[i][j]=0;
				//被标记处路线数为0 
			}
			else{
				a[i][j]=a[i-1][j]+a[i][j-1];
				//状态转移方程,核心是把大问题拆成小部分,学
				//对每一个格子,都考虑上一步是从左边来的,还是从上边来的 
			}
		}
	}
	printf("%lld",a[n][m]);
	return 0;
}

P1007 独木桥(简单模拟+贪心)

没什么好说的

#include 
int l,n,i,min,max,arr[5001];
int main(){
	scanf("0 0",&l,&n);
	if(n==0){
		//特判 
		printf("0");
		return 0;
	}
	for(i=1;i<=n;i++) scanf("%d",&arr[i]);
	if(arr[1]<=l/2){
		min=arr[1];
		max=l-arr[1]+1;
	}
	else{
		min=l-arr[1]+1;
		max=arr[1];
	}
	for(i=2;i<=n;i++){
		if(arr[i]<=l/2){
			if(arr[i]>=min) min=arr[i];
			if(l-arr[i]>=max) max=l-arr[i]+1;	
		} 
		else{
			if(arr[i]>=max) max=arr[i];
			if(l-arr[i]>=min) min=l-arr[i]+1;				
		}
	}
	printf("%d %d",min,max);
	return 0;
}

P1228 地毯填补问题(分治,递归)

该题是我第一次接触分治算法,大概理解了

#include 

int n, k, a[1201][1201];

void dfs(int x1, int y1, int x2, int y2, int X, int Y)
{
    if (x2 - x1 == 1 && y2 - y1 == 1)  //变成了2*2
    {
        if (X == x1 && Y == y1) printf("%d %d 1\n", x2, y2);
        if (X == x1 && Y == y2) printf("%d %d 2\n", x2, y1);
        if (X == x2 && Y == y1) printf("%d %d 3\n", x1, y2);
        if (X == x2 && Y == y2) printf("%d %d 4\n", x1, y1);
        return;
    }
    int x = (x2 - x1 + 1) / 2 + x1 - 1;
    int y = (y2 - y1 + 1) / 2 + y1 - 1;  
    //先求出中间点
    if (X <= x && Y <= y)   //真公主在此时中间点的左上角
    {
        dfs(x1, y1, x, y, X, Y);                    //在左上角面积为原来1/4的小正方形区域内搜索(x,y都为原先的1/2)
        printf("%d %d 1\n", x + 1, y + 1);
        dfs(x + 1, y1, x2, y, x + 1, y);            //右上角
        dfs(x + 1, y + 1, x2, y2, x + 1, y + 1);    //右下角
        dfs(x1, y + 1, x, y2, x, y + 1);            //左下角
    }
    if (X <= x && Y > y)    //真公主在此时中间点的左下角
    {
        dfs(x1, y + 1, x, y2, X, Y);                //左下角
        printf("%d %d 2\n", x + 1, y);              
        dfs(x1, y1, x, y, x, y);                    //左上角
        dfs(x + 1, y1, x2, y, x + 1, y);            //右上角
        dfs(x + 1, y + 1, x2, y2, x + 1, y + 1);    //右下角
    }
    if (X > x && Y <= y)    //真公主在此时中间点的右上角
    {
        dfs(x + 1, y1, x2, y, X, Y);                //右上角
        printf("%d %d 3\n", x, y + 1); 
        dfs(x + 1, y + 1, x2, y2, x + 1, y + 1);    //右下角
        dfs(x1, y1, x, y, x, y);                    //左上角
        dfs(x1, y + 1, x, y2, x, y + 1);            //左下角
    }
    if (X > x && Y > y)     //真公主在此时中间点的右下角
    {
        dfs(x + 1, y + 1, x2, y2, X, Y);            //右下角
        printf("%d %d 4\n", x, y);                  
        dfs(x1, y1, x, y, x, y);                    //左上角
        dfs(x1, y + 1, x, y2, x, y + 1);            //左下角
        dfs(x + 1, y1, x2, y, x + 1, y);            //右上角
    }
}

int main()
{
    int x, y;
    scanf("%d%d%d", &k, &x, &y);
    n = 1;
    for (int i = 1; i <= k; i++)
        n *= 2;  
    dfs(1, 1, n, n, x, y);
    return 0;
}

P1056 排座椅(贪心+桶排)

懒得思考了…看看人家是怎么设数组的吧…

#include 
#include 
int m,n,k,l,d;
int x[1005],y[1005];
//横纵坐标数组 
int c[1005],o[1005];
//桶排要用的数组
int min(int a,int b){
	if(a>=b) return b;
	else return a;
}
int main(){
	int i,j,p;
    scanf("%d%d%d%d%d",&m,&n,&k,&l,&d); 
    for(i=1;i<=d;i++) { 
        int xi,yi,pi,qi; 
        scanf("%d%d%d%d",&xi,&yi,&pi,&qi); 
        if(xi==pi) 
            x[min(yi,qi)]++;
			//x和y数组存放的是,如果隔开这两排/列,能分开几组说话的同学 
            //需要取min,过道与前一个坐标保持一致 
        else 
            y[min(xi,pi)]++; 
    } 
    for(i=1;i<=k;i++){
	//桶排 
        int maxn=-1;
		//为了求出每次的最大值,需要每次扫一遍
        for(j=1;j<m;j++)
            if(y[j]>maxn){ 
                maxn=y[j]; 
                p=j; 
            }
        y[p]=0;
        //这种情况归为0,继续找次于这一种的下一种过道划分方式,直到找到k种 
        c[p]++; 
    } 
    for(i=1;i<=l;i++){ 
        int maxn=-1; 
        for(j=1;j<n;j++) 
            if(x[j]>maxn){ 
                maxn=x[j]; 
                p=j; 
        } 
        x[p]=0;
        o[p]++; 
    } 
    for(i=0;i<1005;i++)
	//输出结果 
        if(c[i]) 
            printf("%d ",i); 
    printf("\n"); 
    for(i=0;i<1005;i++) 
        if(o[i]) 
            printf("%d ",i);
    return 0; 
}

P4136 谁能赢呢?(数学分析)

“最优策略”即每个格子都要走过,这时候只需要判断总格子的个数,个数为奇数则xx胜,个数为偶数则xx胜…

#include 
int n;
int main(){
    while(1){
        scanf("%d",&n);
        if(n==0) return 0;
        if(n%2) printf("Bob\n");
        else printf("Alice\n");
    }
    return 0;
}

P5016 [NOIP2018 普及组] 龙虎斗(四舍五入)

学习四舍五入的方法

#include 
//#include 
long long n,arr[100001],m,i,p1,s1,s2,sum,p2;
int main(){
	scanf("%lld",&n);
	for(i=1;i<=n;i++) scanf("%lld",&arr[i]);
	scanf("%lld%lld%lld%lld",&m,&p1,&s1,&s2);
	for(i=1;i<=n;i++) sum+=arr[i]*(m-i);
	sum+=s1*(m-p1);
    p2=m+(int)(sum*1.0/s2+0.5*(sum>0?1:-1));
//	if(sum>0) p2=m+round(sum*1.0/s2);
//	else p2=m-round(sum*1.0/s2); 
//  用round函数实现四舍五入,只能得72分,原因未知 
	if(p2>n) p2=n;
	if(p2<1) p2=1;
	printf("%lld",p2);
	return 0;

}

P1563 玩具谜题(模拟,分类)

#include 
int m,n,i,j,ans;
char people[100001][11]; 
int cmd[100001][2],dir[100001];
int main(){
	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++)
		scanf("%d%s",&dir[i],&people[i]);
	for(i=0;i<m;i++)
		for(j=0;j<2;j++)
			scanf("%d",&cmd[i][j]);
	for(i=0;i<m;i++){
		if(cmd[i][0]+dir[ans]==0){
			//如果指令和初始朝向都为0,则顺时针转 
			if(ans>=cmd[i][1]) ans-=cmd[i][1];
			else ans=ans+n-cmd[i][1];
		}
		else if(cmd[i][0]+dir[ans]==1){
			//如果指令和初始朝向一个为0,一个为1,则顺时针转 
			if(ans+cmd[i][1]>=n) ans=ans-n+cmd[i][1];
			else ans+=cmd[i][1];
		}
		else if(cmd[i][0]+dir[ans]==2){
			//如果指令和初始朝向都为1,则顺时针转 
			if(ans>=cmd[i][1]) ans-=cmd[i][1];
			else ans=ans+n-cmd[i][1];			
		}
	}
	printf("%s",people[ans]);
	return 0;
}

P2141 珠心算测验(循环、暴力枚举)

#include 
int n,arr[101],check[10001],ans;
int main(){
	int i,j,k;
	scanf("%d",&n);
	for(i=0;i<n;i++) scanf("%d",&arr[i]);
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			if(i==j) continue;
			for(k=0;k<n;k++){
				if(k==i||k==j) continue;
				if(arr[j]+arr[k]==arr[i]){
					if(check[arr[i]]==0) ans++;
					check[arr[i]]=1;
				}
			}
		}
	}
	printf("%d",ans);
	return 0;
}

P1067 多项式输出(分类讨论)

#include 
int n,arr[101],count;
int main(){
	int i;
	scanf("%d",&n);
	for(i=0;i<=n;i++) scanf("%d",&arr[i]);
	for(i=0;i<=n;i++){
		if(n-i!=1&&n-i!=0){
			if(arr[i]<0&&arr[i]!=-1){
				count++;
				printf("%dx^%d",arr[i],n-i);
			}
			else if(arr[i]==-1){
				count++;
				printf("-x^%d",n-i);		
			}
			else if(arr[i]>0&&arr[i]!=1&&count!=0){
				count++;
				printf("+%dx^%d",arr[i],n-i);
			}
			else if(arr[i]==1&&count!=0){
				count++;
				printf("+x^%d",n-i);				
			}
			else if(arr[i]>0&&arr[i]!=1&&count==0){
				count++;
				printf("%dx^%d",arr[i],n-i);				
			}
			else if(arr[i]>0&&arr[i]==1&&count==0){
				count++;
				printf("x^%d",n-i);				
			}
			else if(arr[i]==0);		
		}
		else if(n-i==1){
			if(arr[i]<0&&arr[i]!=-1){
				count++;
				printf("%dx",arr[i],n-i);
			}		
			else if(arr[i]==-1){
				count++;
				printf("-x");
			}
			else if(arr[i]>0&&arr[i]!=1&&count!=0){
				count++;
				printf("+%dx",arr[i]);
			}
			else if(arr[i]>0&&arr[i]!=1&&count==0){
				count++;
				printf("%dx",arr[i]);
			}
			else if(arr[i]>0&&arr[i]==1&&count!=0){
				count++;
				printf("+x");
			}
			else if(arr[i]>0&&arr[i]==1&&count==0){
				count++;
				printf("x");
			}				
			else if(arr[i]==0);				
		}
		else if(n-i==0){
			if(arr[i]>0&&count!=0){
				count++;
				printf("+%d",arr[i]);
			} 
			if(arr[i]>0&&count==0){
				count++;
				printf("%d",arr[i]);
			} 
			else if(arr[i]<0){
				count++;
				printf("%d",arr[i]);
			} 
		}
	}
	return 0;
} 

P1096 Hanoi 双塔问题(乘方高精度)

C语言中的高精度乘法

上方博客可作参考,虽然和如下代码没有什么关系…

#include 
int i,j,n,len=1,arr[10001];
int main(){
	arr[1]=1;
	scanf("%d",&n);
	for(i=1;i<=n+1;i++){
		for(j=1;j<=len;j++)
			arr[j]*=2;
		for(j=1;j<=len;j++){
			if(arr[j]>9){
				if(arr[len]>9) len++;
				arr[j+1]+=arr[j]/10;
				arr[j]%=10;
			}
		}
	}
	arr[1]-=2;
	// 这里只做了一次判断,其实不严谨 
	if(arr[1]<0){
		arr[1]=arr[1]+10-2;
		arr[2]--;
	}
	for(i=len;i>0;i--) printf("%d",arr[i]);
	return 0;
} 

P2058 海港(模拟)

#include 
int s, i, n, t, k, r, w[100001], x[300002], y[300002];
int main(){
    scanf("%d",&n);
    while(n--){
        scanf("%d%d", &t, &k);
        while(k--){
            y[++r] = t; 
            scanf("%d", &x[r]);
            if(!w[x[r]])s++;
            w[x[r]]++;
        }
        while (t - y[i] >= 86400)
            if (!--w[x[i++]])s--;
        /*
        这句话与下面这段代码等效:
        w[x[i]]--;          国籍为当前这个人的国籍的人的数量-1
        if(!w[x[i]])s--;    如果当前这个人的国籍没人,那么答案-1
        i++;                换下一个人
        */
        printf("%d\n", s);
    }
    return 0;
}

P2670 扫雷游戏(简单DFS)

#include 
int m,n;
const int dx[]={1,1,1,0,0,-1,-1,-1};
const int dy[]={1,0,-1,1,-1,0,1,-1};
char arr[101][101];
int main(){
	int i,j,k;
	scanf("%d%d",&m,&n);
	for(i=0;i<m;i++)
		scanf("%s",arr[i]);
	for(i=0;i<m;i++)
		for(j=0;j<n;j++)
			if(arr[i][j]!='*'){
				arr[i][j]-=15;
				for(k=0;k<8;k++)
					if(arr[i+dx[k]][j+dy[k]]=='*')
						arr[i][j]++;				
			}
	for(i=0;i<m;i++)
		printf("%s\n",arr[i]);
	return 0;
} 

你可能感兴趣的:(数据结构与算法)