A:跑步

知识点:最大公约数、最小公倍数、递归、函数

解题思路:要三位同学在第x天相遇,就需要求出三个数的最小公倍数,可以先求出两个的最小公倍数,其结果与第三个数再求出最小公倍数即可。注意假设两个数为a,b则,ab=最大公约数(a,b)最小公倍数(a,b),故最小公倍数(a,b)=a*b/最大公约数(a,b),而最大公约数需要使用辗转相除法(递归来解决)。

参考代码:

#include<bits/stdc++.h>
using namespace std;
int a,b,c;
int gcd(int x,int y){
    if(x%y==0) return y;
    return gcd(y,x%y);
} 
int main(){
    cin>>a>>b>>c;
    int x=a*b/gcd(a,b);
    int y=x*c/gcd(x,c);
    cout<<y; 
    return 0;
}

B:文具购买

知识点:枚举

解题思路:题目要求abc的最小值尽可能大,所以就要让它们的最小值越接近n/14越好,如果abc的最小值为n/14时无解,则让ab,c的最小值为n/14−1,以此类推,直到有解为止。所以a从n/14开始往下枚举最小值然后依次枚举b,c,一旦遇到有解就输出,结束程序。此时的解就是最优解。注意枚举范围,b从a到n/4,c从a到n/3。最后如果无解,输出−1。

代码:

#include<bits/stdc++.h>
using namespace std;
int n;//n元钱
int main() {
    cin>>n;
    for(int i=n/14; i>=0; i--) {
        for(int j=i; j<=n/4; j++) {
            for(int k=i; k<=n/3; k++) {
                if(i*7+j*4+k*3==n) {
                    cout<<i<<' '<<j<<' '<<k<<endl;
                    return 0;
                }
            }
        }
    }
    cout<<-1;
    return 0;
}

C:序列

知识点:贪心

解题思路:题目让我们求在 [li,ri]中至少有ci个数。我们可以将所有的区间按右端点的大小,从小到大排列。如果当前区间已经满足了它的要求,那么它其中的数的位置可以随意摆放,又因为它之后的区间的右端点的值比当前区间右端点大,所以我们贪心地选择当前区间最右端的数,可以尽量满足后面区间的条件。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,f[1001],maxn,ans;
struct node{
    int l,r,c;
    bool operator<(const node& b)const{
        return r<b.r;//按照右区间进行排序 
    }
}a[1001];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i].l>>a[i].r>>a[i].c;
        maxn=max(maxn,a[i].r);
    }
    sort(a+1,a+1+n);
    //贪心策略:尽量靠后的放数字
    for(int i=1;i<=n;i++){
        int cnt=0;//统计个数
        for(int j=a[i].r;j>=a[i].l;j--){
            if(f[j]){
                cnt++;
                if(cnt>=a[i].c){
                    break;    
                }
            }
        } 
        if(cnt<a[i].c){//个数不足 
            for(int j=a[i].r;j>=a[i].l;j--){
                if(!f[j]){
                    f[j]=1;
                    cnt++;
                    if(cnt>=a[i].c){
                        break;
                    }
                }
            } 
        }
    } 
    for(int i=1;i<=maxn;i++){
        if(f[i])ans++;
    }
    cout<<ans;
    return 0;
}

D:棋盘

知识点:递归、深度优先搜索

解题思路:

对于每个已经到达的位置,若其金币超过记忆数组的存储数据,则不需要深搜,因为这一步不是最优解,前面已经走过比本次更优的解。然后记录到达该位置的最优解,若走到了终点就进行答案判断结束搜索。最后考虑新的坐标,若其未越界未被访问,就考虑:

下一个块没有颜色 对于当前状态,有以下状态以及操作: (1) 当前踩的块是被施法过的,不能施法,继续寻找其他扩展块 (2) 当前踩的块没有被施法过,对下一个块染成和当前块一样的颜色,代价+2 下一个块有颜色 对于当前状态,有以下状态以及操作: (1) 当前块与下一个块颜色相同,扩展且无需任何代价 (2) 当前块与下一个块颜色相同,扩展且无需任何代价

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;//n*n矩阵 m个数据
int a[1001][1001];//存放数据
bool b[1001][1001];//标记
int c[1001][1001];//最小花费金币
int d[][2]={{0,1},{0,-1},{1,0},{-1,0}};
int ans=INT_MAX;//答案 
void dfs(int x,int y,int money,bool magic){
    if(money>=c[x][y]) return;
    c[x][y]=money;
    if(x==n&&y==n){
        ans=min(ans,money);
        return;
    }
    for(int i=0;i<4;i++){
        int xx=x+d[i][0],yy=y+d[i][1];
        //未越界 未来过  
        if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&!b[xx][yy]){
            if(a[xx][yy]==-1 && magic)  continue;//新的位置是无色 上一次使用过魔法
            b[xx][yy]=1;
            if(a[xx][yy]==-1){//新位置为无色 
                a[xx][yy]=a[x][y];
                dfs(xx,yy,money+2,1);//这个位置使用过魔法了 
                a[xx][yy]=-1;    
            }else{
                if(a[xx][yy]==a[x][y]) dfs(xx,yy,money,0);
                else dfs(xx,yy,money+1,0);
            }             
            b[xx][yy]=0; 
        } 
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            a[i][j]=-1;
            c[i][j]=INT_MAX;
        }
    }
    for(int i=1,x,y,z;i<=m;i++){
        cin>>x>>y>>z;
        a[x][y]=z;
    }
    //1,1的位置搜索money为0,上一次没使用魔法0
    dfs(1,1,0,0);
    if(ans==INT_MAX)cout<<-1;
    else cout<<ans;
    return 0;
}
Copyright ©图灵之星 2024,转载需注明出处该文件修订时间: 2025-02-22 21:49:41

results matching ""

    No results matching ""