计蒜客----蓝桥杯模拟省赛(四)

B分蛋糕
解法一:2个数的最大公约数即最终的蛋糕质量。
证明:
质量相等则为公约数。
如果在最大公约数这里次数不是最小的,那么在假设更小一点的公约数这里次数是最小的,那么最大公约数除以这个公约数,会得到a,也就是在最大公约数这里多除了一个a,才得到答案,那么次数就不是最小的了,所以在最大公约数这里次数是最大的。
get:反证法

#include<cstdio>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
int gcd(int x,int y)
{
    return y==0? x:gcd(y,x%y);
}
int done(int a)
{
    int ans=0;
    while(a%3==0){
        a=a/3;
        ans++;
    }
    while(a%5==0){
        a=a/5;
        ans++;
    }
    while(a%2==0)
    {
        a=a/2;
        ans++;
    }
    return ans;
}
int main(void)
{int c=gcd(540000,2430);
cout<<c<<endl;
cout<<done(540000/c)+done(2430/c)<<endl;
return 0;

}

解法二:bfs
错误bfs,忘记了bfs中的基本是每次放入队列的都是step只差1

#include<bits/stdc++.h>
using namespace std;
struct re{int x,y;
bool operator<(const re &a)const {return x<a.x;}
};
int ce[]={0,2,3,5};
map<re,int>exi;
//queue<re>all;
queue<re>all;
int  bfs()
{
    while(!all.empty())
    {re tem=all.front();
    all.pop();
  //  printf("%d %d\n",tem.x,tem.y);
        for(int i=1;i<=4;i++)
        {  re get=tem;
        int times=0;
          if(i!=4&&(get.x%ce[i]==0)){get.x/=ce[i];times++;}
              for(int f=1;f<=4;f++)
             {   if(f!=4)
                 if(get.y%ce[f]==0){get.y/=ce[f];times++;}
                 if(exi[get]==0)
                    {exi[get]=exi[tem]+times;

                    all.push(get);
                 }
                 if(get.x==get.y)return exi[get];
              }

        }
    }
    return -1;
}
int main(void)
{
    re tem;
    tem.x=540000;
    tem.y=2430;
    exi[tem]=1;
    all.push(tem);
    cout<<bfs()-1<<endl;
    return 0;
}


正确bfs,但是也查bug查了好久,原因是用map和结构体的话排序规则要定义完整了,否则会出错。

#include<bits/stdc++.h>
using namespace std;

struct re{
int x,y;
bool operator<(const re &a)const {return x==a.x? y<a.y:x<a.x;}//这里用 return x<a.x的时候就出错了
 };
map<re,int>exi;
queue<re>all;
int bfs()
{
    while(!all.empty())
    {
        re get=all.front();
        all.pop();
       // cout<<get.x<<"   "<<get.y<<endl;
        if(get.x==get.y)return exi[get];
        if(get.x%2==0)
        {re tem=get;
             tem.x=get.x/2;
            if(exi[tem]==0){exi[tem]=exi[get]+1;all.push(tem);}
        }
        if(get.x%3==0)
        {re tem=get;
            tem.x=get.x/3;
            if(exi[tem]==0){exi[tem]=exi[get]+1;all.push(tem);}
        }
        if(get.x%5==0)
        {re tem=get;
            tem.x=tem.x/5;
            if(exi[tem]==0){exi[tem]=exi[get]+1;all.push(tem);}
        }
        if(get.y%2==0)
        {re tem=get;
            tem.y=tem.y/2;
            if(exi[tem]==0){exi[tem]=exi[get]+1;all.push(tem);}
        }
        if(get.y%3==0)
        {re tem=get;
            tem.y=tem.y/3;
            if(exi[tem]==0){exi[tem]=exi[get]+1;all.push(tem);}
        }
        if(get.y%5==0)
        {re tem=get;
            tem.y=get.y/5;
            if(exi[tem]==0){exi[tem]=exi[get]+1;all.push(tem);}
        }

    }
}
int main(void)
{re tem;
tem.x=540000;
tem.y=2430;
exi[tem]=1;
    all.push(tem);

    cout<<bfs()-1;
}

C数独
首先要知道数独游戏的规则,在0处填数,要满足每行每列,每个3*3小方阵里没有重复的数。
第一思路肯定是用dfs,但是却没有做出来,后来查出原因,是在某个地方,没有直接返回,又继续进行而出错。
我的代码

#include<cstdio>
#include<algorithm>
int mp[10][10];
bool exi_x[20][20],exi_y[20][20];
bool check(int x,int y,int num)
{
    int qx=(x-1)/3*3+1;
    int qy=(y-1)/3*3+1;
    int mx=((x-1)/3+1)*3;
    int my=((y-1)/3+1)*3;
    for(int i=qx;i<=mx;i++)
        for(int d=qy;d<=my;d++)
          if(mp[i][d]==num)return 1;
    return 0;
}
int ans=0;
void write()
{
    for(int i=1;i<=9;i++)
        for(int d=1;d<=9;d++)
        printf("%d%s",mp[i][d],d==9? "\n":"  ");
    printf("\n");
}
void dfs(int x,int y)
{//if(ans>20)system("pause");

    if(x==10&&y==1){ans++;printf("ans=%d\n",ans);write();return ;}

int nx=x,ny=y;
if(y==9){nx++;ny=1;}
else {ny++;}
    if(mp[x][y]!=0){dfs(nx,ny);return;}//就是这里少了return,结果出错。

    for(int i=1;i<=9;i++)
    {
        if(exi_x[x][i]||exi_y[y][i])continue;
        if(check(x,y,i))continue;
        mp[x][y]=i;
        exi_x[x][i]=1;
        exi_y[y][i]=1;
        dfs(nx,ny);
        mp[x][y]=0;
        exi_x[x][i]=0;
        exi_y[y][i]=0;
    }
}
int main(void)
{
    for(int i=1;i<=9;i++)
        for(int d=1;d<=9;d++)
    {
        scanf("%d",&mp[i][d]);
        exi_x[i][mp[i][d]]=1;
        exi_y[d][mp[i][d]]=1;
    }
  //  printf("kkkk\n");
    dfs(1,1);
    printf("ans=%d\n",ans);
    return 0;
}

看了题解给出的代码,我觉得有可学习之处

#include<cstdio>
using namespace std;
int mp[20][20];
int ans=0;
bool check(int x,int y,int det)
{
    for(int i=0;i<9;i++)
        if(mp[x][i]==det||mp[i][y]==det)return 1;
    int qx=(x/3*3);
    int qy=(y/3*3);
    for(int i=qx;i<qx+3;i++)
        for(int d=qy;d<qy+3;d++)
        if(mp[i][d]==det)return 1;
    return 0;
}
void dfs(int now)
{if(now==81)
{
    ans++;
    return ;
}
    int x=now/9;
int y=now%9;   //这种处理方式很适合矩阵
if(mp[x][y]!=0){dfs(now+1);return;}

    for(int i=1;i<=9;i++)
    {
        if(check(x,y,i))continue;
        mp[x][y]=i;
        dfs(now+1);
        mp[x][y]=0;
    }
}
int main(void)
{
    for(int i=0;i<9;i++)
        for(int d=0;d<9;d++)
        scanf("%d",&mp[i][d]);
        dfs(0);
        printf("%d\n",ans);
        return 0;
}

C 采药,背包问题
不会做的原因是多dp的思想理解不够深刻
dp[x][y][k]表示的是在x,y的位置,装满k物体时的价值

D。时针和分针相碰,细节问题,对于这种题真的不嫩马虎,贪快,就算把24个都想一遍也不忙
题目问时针与分针碰撞了几次,并且规定如果在在开始处相互撞击算撞击,如果在末尾时撞击不算,
仔细想,那就是从11点到12点 和 23点到24点它撞击0次。

#include<cstdio>
#include<algorithm>
using namespace std;
int main(void)
{int cas;
    scanf("%d",&cas);
    while(cas--)
    {int n,m;
        scanf("%d  %d",&n,&m);
        if(m<12){printf("%d\n",m-n);continue;}
        if(m==12){printf("%d\n",m-n-1);continue;}
        if(n<12&&m<24){printf("%d\n",m-n-1);continue;}
        if(n>=12&&m<24){printf("%d\n",m-n);continue;}
        if(m==24)
        {if(n<12)
            printf("%d\n",m-n-2);
            if(n>=12)printf("%d\n",m-n-1);
            continue;
    }
    }
    return 0;
}

给的题解更好理解,就是经过那个直接减去

#include<cstdio>
using namespace std;
int main(void)
{int cas;
    scanf("%d",&cas);
    while(cas--)
    {int n,m,ans;
     scanf("%d %d",&n,&m);
     ans=m-n;
     if(n<=11&&m>=12)ans--;
     if(n<=23&&m>=24)ans--;
     printf("%d\n",ans);
    }
    return 0;
}

G.暴力搜索加打表

#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<iostream>
using namespace std;
int all[20];
bool vi[20];
int ans;
set<string>allans[10002];
void check()
{int sum1=0,sum2=0;

    for(int i=1;i<=5;i++)
    {
        sum1=sum1*10+all[i];
        sum2=sum2*10+all[i+5];
    }
   // printf("sum1=%d   sum2=%d\n",sum1,sum2);
    //if(sum1>20000)system("pause");
    if(sum1%sum2)return ;
     string tem;
     for(int i=0;i<5;i++)tem.push_back(all[i+1]+'0');
     tem.push_back('/');
     for(int i=6;i<=10;i++)tem.push_back(all[i]+'0');
     tem.push_back('=');
     string add;
     //cout<<tem<<endl;
     allans[sum1/sum2].insert(tem);
}
void dfs(int th)
{if(th==11)
{
   check();
    return;
}
    for(int i=0;i<=9;i++)
    {
        if(vi[i]==0){all[th]=i;vi[i]=1;dfs(th+1);vi[i]=0;}
    }
}
int main(void)
{int cas;
    scanf("%d",&cas);
    dfs(1);
    while(cas--)
    {int a;
    ans=0;
        scanf("%d",&a);

        if(allans[a].size()==0)printf("No expression!\n");
        else{
            set<string>::iterator it=allans[a].begin();
            for(;it!=allans[a].end();it++)
            {
                cout<<*it;
                printf("%d\n",a);
            }
        }
    }
    return 0;
}

H题,经典题目,4瓶可乐盖子送1瓶可乐,问喝n瓶最少需要买几瓶
这题就是要想明白,买了4瓶,就会送一瓶,那么要再买3瓶,就得到一瓶,这时候又再买3瓶,得到一瓶。所以就是第一次买4瓶作为一个动力源,然后每次都会再买3瓶后得到1瓶,而这一瓶也会作为下一个4瓶盖中的一个。
设m为要买的总数,
即当m>4时,要买的基本瓶数为(m-4)/4*3; 额外的瓶数为(m-4)%4若不为0,就要减1,因为前3个中得到了一个空的,如果恰好为0,则不处理。
当m<=4,自然是另一种法则。

#include<cstdio>
#include<algorithm>
using namespace std;
int main(void)
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {int a,b;
        scanf("%d %d",&a,&b);
        if(a<=4){printf("%d\n",a*b);continue;}
        int c=a-4;
        long long int f=c/4*3;
        f=f+4;
        if(c%4)f=f+c%4-1;
        printf("%lld\n",f*b);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43235540/article/details/88617491
今日推荐