第38周周赛
B
两种操作
我直接想到用BFS做,不过最后超时了
过了14/16
#include
#include using namespace std;
int a,b;
struct node{int a;int layer=0;
} ;
queue <node> q;
int ans;
void dfs(int a){node a1,a2;a1.a=a*2;a1.layer=1;a2.a=a-1;a2.layer=1;if(a-1>0&&a<b){q.push(a1);q.push(a2);}else if(a-1>0&&a>b)q.push(a2);elseq.push(a1);while(!q.empty()){//非空的时候auto m=q.front();q.pop();if(m.a==b){ans=m.layer;break;} node m1,m2;m1.a=m.a*2;m1.layer=m.layer+1;m2.a=m.a-1;m2.layer=m.layer+1;if(m.a-1>0&&m.a<b){q.push(m1);q.push(m2);}else if(m.a-1>0&&m.a>b)q.push(m2);elseq.push(m1);}
}int main(){cin>>a>>b;dfs(a);cout<<ans;return 0;
}
看了题解之后我发现我写的bfs很不好,因为我遗忘了怎么设置步长,就用了一个结构体,这样会导致很多重复的。比如说好几种方法都能走到x,那么x会出现很多次,就是大量的无用计算。因此需要借鉴地图bfs中的二维数组,在本题中创建一个一位数组用于记录step,同时这个step也可以标记哪些点走过,避免重复计算。
特别注意!!!
再写下面代码的时候,我仍遇到了一些问题,我感觉很重要,需要注意:
- 要防止数组越界,在t2时很容易越界,因此需要判断t2是否在数组范围内
- 知道了上式,我修改了代码如下
if p[t*2]==0&&t*2
这仍然错误。因为我忽略了短路的性质,该判断语句首先会执行p[t2]这个如果越界就直接没了。但是如果写的是t-12那么就会先判断t
#include
#include using namespace std;const long long N=1e6;int n,m;
int p[N];
queue <int> q;void bfs(int a){if(a-1>0){q.push(a*2);q.push(a-1);p[a*2]=1;p[a-1]=1;}else{q.push(a*2);p[a*2]=1;}//队列和步长初始化while(1){auto t=q.front();q.pop();if(t==m){cout<<p[t];break;}if(t-1>0&&t<=m){if(t-1<N&&p[t-1]==0){q.push(t-1);p[t-1]=p[t]+1;}if(t*2<N&&p[t*2]==0){q.push(t*2);p[t*2]=p[t]+1;}}else if(t-1<N&&t-1>0&&t>m&&p[t-1]==0){q.push(t-1);p[t-1]=p[t]+1;}else {if(t*2<N&&p[t*2]==0){//只有之前没有走过才能push进去 q.push(t*2);p[t*2]=p[t]+1;}}} }int main(){cin>>n>>m;if(n>=m){cout<<n-m;return 0;}bfs(n);return 0;
}
另:贪心做法
#include using namespace std;//贪心的思路是逆推,从m推n
/*
m可以执行的操作有+1和除以2
如果m比n小,那么就执行加一,这很好理解
如果m比n大,如果m能被2整除,那么就用除以2
不然就+1 */ int n,m;int main(){cin>>n>>m;int ans=0;while(n!=m){if(m>n&&m%2==0){m/=2;ans++;}else{m++;ans++;}}cout<<ans;return 0;
}
C
最近做题目有点嚣张行,看了样例都过了就直接提交了,结果正确率很低,蓝桥杯就只能提交一次,因此要保证准确率,以后需要多验证一会。
本题思路写在代码里了。
需要注意的点是:(就是我提交出错的几个点)
1.
这里加了一个plus就是防止出现00这样的数据,因为刚开始就满足分割条件,直接不进入循环了,而我在循环外面没有设置任何的j++,导致死循环。
2.
这个部分我一开始是放在for i循环内 for j外
我当时想着的是把所有分组全部都分好了再放到外面判断,但是对于00020200这样子的数据,会分为0002,02之后然后继续分00,而00不满足直接break了,导致最后错误。
后来我就在想,如何修改,还得判断后面都是0吗?
但是,其实很简单,放进for j循环里就行了。
为什么呢,因为我们已经确定了分段的数量和每个分段的和,因此只要for j中遍历了满足要求的数量的分段数,那么一定加起来就是总和sum,而后面的一定都是0,不需要把所有的字符都遍历一遍。如果不这样做,就会出现后面都是0但是都遍历了,就出错了。
上面这点一定要注意!!!
/*
如果需要将一段字符分割成为和相同的几段
那么每一段和的公式就是 字符串元素总和/段数*/#include using namespace std;string s;
int n;
int sum=0;
int flag=0;int main(){cin>>n;cin>>s;for(int i=0;i<n;i++){sum+=s[i]-'0';//字符串元素总和 } for(int i=2;i<=n;i++){//i为能分成的段数,一个n长度的字符段最多分为n段 if(sum%i!=0)continue;//总和没法分为i段,就继续遍历段数 int sec_target=sum/i;//目标每段的和int sec_num=0;//记录当前有多少段 (为下一个for准备)for(int j=0;j<n;){//对每个元素进行枚举//从头开始就行,不用担心分段会对元素顺序造成影响,//因为每一个分段的值都确定了,就从每段开始枚举就可以int sec_sum=0;//标记当前段总和 int plus=0;//标记一下是否进入过循环 while(sec_sum<sec_target){sec_sum+=s[j++]-'0';plus++;}if(sec_sum>sec_target)break;//如果第一组就不能满足,直接break进入下一个循环 elsesec_num++;//增加段数if(!plus)j++; if(sec_num==i){flag=1;break;//找到了这样的分法,直接break }}}if(flag)cout<<"YES";elsecout<<"NO";return 0;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!


