【清北前紧急补课3】水题集锦

1.均分纸牌

题目描述

NNN 堆纸牌,编号分别为 1,2,…,N1,2,…,N1,2,,N 。每堆上有若干张,但纸牌总数必为 NNN 的倍数。可以在任一堆上取若干张纸牌,然后移动。

移牌规则为:在编号为 111 堆上取的纸牌,只能移到编号为 222 的堆上;在编号为 NNN 的堆上取的纸牌,只能移到编号为 N−1N-1N1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。

现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

例如 N=4N=4N=4 , 444 堆纸牌数分别为:

999 ② 888 ③ 171717 ④ 666

移动 333 次可达到目的:

从 ③ 取 444 张牌放到 ④ ( 9,8,13,109,8,13,109,8,13,10 )-> 从 ③ 取 333 张牌放到 ②( 9,11,10,109,11,10,109,11,10,10 )-> 从 ② 取 111 张牌放到①( 10,10,10,1010,10,10,1010,10,10,10 )。

输入输出格式

输入格式:

两行

第一行为: NNN ( NNN 堆纸牌, 1≤N≤1001 \le N \le 1001N100 )

第二行为: A1,A2,…,AnA_1,A_2, … ,A_nA1,A2,,AnNNN 堆纸牌,每堆纸牌初始数, l≤Ai≤10000l \le A_i \le 10000lAi10000 )

输出格式:
一行:即所有堆均达到相等时的最少移动次数。

特别好理解的。是一个很典型的贪心算法。这个题应该想到用每个数都减去平均张数,题目就变成了要移动的数量。正数表示要移走,负数表示要移过来。如果本来就有0张怎么办呢?那么就要有过滤这个步骤了。

while(a[i]==0&&i<n)i++;//过滤掉左边的0
while(a[j]==0&&j>1)j--;//过滤掉右边的

当然在移牌过程中也不能忘记过滤每个过程中产生的0牌。

while(a[i]==0&&i<j) i++;

那么代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int ave,n,a[110];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];ave+=a[i];
    }
    ave=ave/n;
    for(int i=1;i<=n;i++) a[i]-=ave;
    int i=1,j=n;
    int step;
    while(a[i]==0&&i<n)i++;
    while(a[j]==0&&j>1)j--;
    while(i<j){
        a[i+1]+=a[i];
        a[i]=0;
        step++,i++;
        while(a[i]==0&&i<j) i++;
    }
    cout<<step;
}

用for循环写的版本如下

#include<iostream>
using namespace std;
int n,w,i,j,a[10010],step;
int main(){
    cin>>n;
    for(i=1;i<=n;i++){
        cin>>a[i];w+=a[i];
    }
    w/=n;
    for(i=1;i<=n;i++) a[i]-=w;
    i=1;j=n;
    for(i=1;i<=n;i++){
        if(a[i]!=0){
            a[i+1]+=a[i];
            a[i]=0;
            step++;
        }
    }
    cout<<step;
}

2.迷宫和走迷宫(我也不知道这是一个什么顺序了做着玩吧)

迷宫就直接贴代码就好了,反正就是裸的dfs

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,t,sx,sy,fx,fy,sum=0;
int flag[101][101],trap1,trap2;
void search(int i,int j){
    if(i==fx&&j==fy){
        sum++;
        return;
    }
    else {
    flag[i][j]=1;
    if((j!=m)&&(flag[i][j+1]==0)) search(i,j+1),flag[i][j+1]=0;//you 
    if((i!=n)&&(flag[i+1][j]==0)) search(i+1,j),flag[i+1][j]=0;//xia
    if((i!=1)&&(flag[i-1][j]==0)) search(i-1,j),flag[i-1][j]=0;//shang
    if((j!=1)&&(flag[i][j-1]==0)) search(i,j-1),flag[i][j-1]=0;//zuo
    }
}
int main(){
    cin>>n>>m>>t;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
        flag[i][j]=0;}
    
    cin>>sx>>sy>>fx>>fy;
    for(int i=1;i<=t;i++){
        cin>>trap1>>trap2;
        flag[trap1][trap2]=1;
    }
    search(sx,sy);
    cout<<sum;
} 

走迷宫就比迷宫多一个输出路径的操作

注意优先级:左上右下

设置一个bool变量pd来判断有没有路径。用一个step来记录步数。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int m,n,a[16][16];
int a1[1001],b1[1001];
int bix,biy,enx,eny;
bool pd;

void read(){
    cin>>m>>n;
    for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++){
        cin>>a[i][j];
    }
    cin>>bix>>biy;
    cin>>enx>>eny;
}

void print(int p){
    pd=1;
    for(int i=0;i<p;i++){
       cout<<"("<<a1[i]<<","<<b1[i]<<")->";
    }
    cout<<"("<<enx<<","<<eny<<")";
    cout<<endl;
}

void search(int x,int y,int step){
    if (x < 1 || y < 1 || x>m || y>n) return;
    if(x==enx&&y==eny){
        print(step);
        return;
    }
    if(a[x][y]==1){
            a1[step]=x;b1[step]=y;
            a[x][y]=0;
            search(x,y-1,step+1);
            search(x-1,y,step+1);
            search(x,y+1,step+1);
            search(x+1,y,step+1);
            a[x][y]=1;
        }
}

int main(){
    read();
    search(bix,biy,0);
    if(pd==0) cout<<"-1";
}

3.跳石头

题目背景

一年一度的“跳石头”比赛又要开始了!

题目描述

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 NNN 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 MMM 块岩石(不能移走起点和终点的岩石)。

输入输出格式

输入格式:

第一行包含三个整数 L,N,ML,N,ML,N,M ,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1L \geq 1L1 且 N≥M≥0N \geq M \geq 0NM0 。

接下来 NNN 行,每行一个整数,第 iii 行的整数 Di(0<Di<L)D_i( 0 < D_i < L)Di(0<Di<L) , 表示第 iii 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输出格式:

一个整数,即最短跳跃距离的最大值。

典型的二分题。二分查找,需要写一个judge函数,来判断移走的个数。若是移走的个数符合要求,记录下来,再搜索其他的是否符合要求,输出最合适的值。

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int l,n,m,a[1000010],i,sum=0,mid;
int s,e;

bool judge(int x){
    int time=0;
    int i=0;
    int now=0;
    while(i<n+1){
        i++;
        if(a[i]-a[now]<x){
            time++;
        }
        else now=i;
    }
    if(time>m) return false;
    else return true;
    
}
int main(){
    cin>>l>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    a[n+1]=l;s=1;e=l;
    while(s<=e){
        mid=(s+e)/2;
        if(judge(mid)){
            sum=mid;
            s=mid+1;
        }
        else e=mid-1;
    }
    cout<<sum<<endl;
}

猜你喜欢

转载自www.cnblogs.com/civilization-ga/p/9334477.html