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;
}