当前位置:   article > 正文

2022RoboCom世界机器人开发者大赛-本科组(初赛)_2022 robocom 世界机器人开发者大赛-本科组

2022 robocom 世界机器人开发者大赛-本科组

1、不要浪费金币

题目分析:

没啥好分析的,从前往后遍历就行

 C++代码如下:

  1. #include<iostream>
  2. using namespace std;
  3. const int N=1010;
  4. int a[N];
  5. int main(){
  6. int n,m;
  7. cin>>n>>m;
  8. for(int i=1;i<=n;i++)cin>>a[i];
  9. int sum=0,cnt=0;
  10. for(int i=1;i<=n;i++){
  11. if(sum+a[i]>m){//如果加上当前的金币数后sum>m,则需要去消费一次
  12. cnt++;//消费次数+1
  13. sum=0;//sum重置为0
  14. }
  15. sum+=a[i];//加上当前的金币数
  16. }
  17. cout<<cnt<<endl;
  18. return 0;
  19. }

2、智能服药助手

题目分析 :

本题保证按照时间递增的顺序给出每个时间的服用药物计划,所以我们从前往后做就可以,不用考虑时间问题

用一个数组last[],last[i]记录上一次服用药物i的时间

对于每个时间点,对当前时间点服用的药物进行一次时间判断即可

C++代码如下:

  1. #include<iostream>
  2. #include<cstring>
  3. using namespace std;
  4. const int N=1010;
  5. int last[N],b[N];//last[i]表示上一次服用药物i的时间
  6. int n,m;
  7. int main(){
  8. cin>>n>>m;
  9. for(int i=1;i<=n;i++)cin>>b[i];//第i种药物服用的间隔时间为b[i]
  10. memset(last,-1,sizeof last);//初始化为-1
  11. while(m--){
  12. int t,k;
  13. cin>>t>>k;//在t时间服用k种药物
  14. while(k--){
  15. int x;
  16. cin>>x;
  17. //1、间隔时间为0 2、未服用过该药物 3、间隔时间足够了,都可以服用该药物
  18. if(b[x]==-1||last[x]==-1||t-last[x]>=b[x])last[x]=t;
  19. //否则不可服用
  20. else printf("Don't take %d at %d!\n",x,t);
  21. }
  22. }
  23. return 0;
  24. }

 3、跑团机器人

题目分析:

一个字符串模拟题,详情看注释

 C++代码如下:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<map>
  4. using namespace std;
  5. map<int,int> cnt;//cnt[i]存储第i种骰子被掷的总数
  6. int maxx,minn;//存储点数的最大最小值
  7. void solve(string s){
  8. int i=0,n=s.size();
  9. int flag=1;//flag为当前指令的正负号,1为正,-1为负
  10. while(i<n){
  11. int pre=0,last=0;
  12. //读取数字字符,存在pre中,isdigit(c)判断c是否是数字字符,是就返回true
  13. while(i<n&&isdigit(s[i]))
  14. pre=pre*10+s[i]-'0',i++;
  15. //如果数字后面是d,说明是这一个指令
  16. if(s[i]=='d'){
  17. if(pre==0)pre=1;//d前面没有数字时,默认为1
  18. i++;
  19. //读取d后面的数字,存在last中
  20. while(i<n&&isdigit(s[i]))
  21. last=last*10+s[i]-'0',i++;
  22. //last面骰子的掷数增加pre
  23. cnt[last]+=pre;
  24. if(flag==1){//pre前面符号为正时
  25. minn+=pre;//(pre*1最小)
  26. maxx+=pre*last;//(pre*last最大)
  27. }else{//pre前面符号为负
  28. minn-=last*pre;
  29. maxx-=pre;
  30. }
  31. }else{//读取完pre后停止在'+'或'-'或越界,说明是一个常量,更新maxx和minn
  32. maxx+=flag*pre;
  33. minn+=flag*pre;
  34. }
  35. if(i<n-1){//如果i停在'+'或者'-',则更新flag,flag作为下一个数字前的符号
  36. if(s[i]=='+')flag=1;
  37. else if(s[i]=='-')flag=-1;
  38. i++;
  39. }
  40. }
  41. }
  42. int main(){
  43. string s;
  44. cin>>s;
  45. solve(s);
  46. for(auto t:cnt)
  47. cout<<t.first<<" "<<t.second<<endl;
  48. cout<<minn<<" "<<maxx<<endl;
  49. return 0;
  50. }

4、攻略分队

题目分析:

将6支队伍(可能不足六只)按要求分成两组,dfs深搜出所有可行的方案,然后用结构体存储起来,写一个cmp函数用于按照题意进行排序,最后输出所有方案种的第一个就可,不存在就输出GG

C++代码如下:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N=10;
  6. int a[N][3],b[N];
  7. int cnt;
  8. struct node{
  9. int mt[2],zh[2],gb[2];//主坦克,指挥,工兵
  10. //mt[0],zh[0],gb[0]表示第1组的信息,mt[1],zh[1],gb[1]表示第2组的信息,
  11. int sum[2];//sum[0]:讨伐欧文的人数 sum[1]:讨伐亚特的人数
  12. string ch[2];//每一组的队伍编号用字符串记录,方便排序和输出
  13. }ans[1200],s;
  14. bool cmp(node x,node y){
  15. int t1=(x.zh[0]&&x.zh[1]&&x.gb[1]&&x.gb[0]);//方案x是否满足条件1
  16. int t2=(y.zh[0]&&y.zh[1]&&y.gb[1]&&y.gb[0]);//方案y是否满足条件1
  17. if(t1!=t2)return t1>t2;
  18. if(!t1){//条件1无法满足
  19. t1=(x.zh[0]&&x.zh[1]);//方案x是否满足条件2
  20. t2=(y.zh[0]&&y.zh[1]);//方案y是否满足条件2
  21. if(t1!=t2)return t1>t2;
  22. }
  23. //二者都满足条件1或两者都满足条件2或两者都不满足条件2,然后判断条件3
  24. if(abs(x.sum[0]-x.sum[1])!=abs(y.sum[0]-y.sum[1]))
  25. return abs(x.sum[0]-x.sum[1])<abs(y.sum[0]-y.sum[1]);
  26. //满足条件3的方案不唯一,然后判断条件4
  27. t1=(x.sum[0]>x.sum[1]);
  28. t2=(y.sum[0]>y.sum[1]);
  29. if(t1!=t2)return t1>t2;
  30. //满足条件4的方案不唯一,然后判断条件5
  31. return x.ch[0]<y.ch[0];
  32. }
  33. void dfs(int x,node y){
  34. if(x==7){//六支队伍都搜完了
  35. if(y.mt[0]>0&&y.mt[1]>0)//判断一下是否每组都有一个mt(主坦克)
  36. ans[cnt]=y,cnt++;//n记录满足条件的方案数
  37. return;
  38. }
  39. if(!b[x]){//如果第x支队伍不存在,则直接看下一个队伍
  40. dfs(x+1,y);
  41. return;
  42. }
  43. for(int i=0;i<=1;i++){//考虑将第x支队伍给第1组还是第2组
  44. node t=y;
  45. t.sum[i]+=b[x];//人数加上第x支队伍的人数
  46. t.mt[i]+=a[x][0];//mt数量加上第x支队伍的mt数
  47. t.gb[i]+=a[x][1];//gb数量加上第x支队伍的gb数
  48. t.zh[i]+=a[x][2];//zh数量加上第x支队伍的zh数
  49. t.ch[i]+=char(x+'0');//记录队伍编号
  50. t.ch[i]+=" ";//加上空格,方便输出
  51. dfs(x+1,t);
  52. }
  53. }
  54. int main(){
  55. for(int i=1;i<=6;i++)scanf("%d",&b[i]);
  56. for(int i=1;i<=6;i++){
  57. string ch;
  58. cin>>ch;
  59. //a[i][0],a[i][1],a[i][2]分别记录第i支队伍的mt数,gb数,zh数
  60. for(int j=0;j<3;j++)
  61. a[i][j]=(ch[j]-'0');
  62. }
  63. dfs(1,s);
  64. if(cnt){
  65. sort(ans,ans+cnt,cmp);//给所有方案排序
  66. string res1,res2;
  67. res1=ans[0].ch[0],res2=ans[0].ch[1];
  68. //不能有多余的空格,所以都要删除最后一个空格,然后再输出
  69. res1.erase(res1.end()-1),res2.erase(res2.end()-1);
  70. cout<<res1<<"\n"<<res2;
  71. }else printf("GG\n");
  72. return 0;
  73. }

5、树与二分图

题目分析:

 给定一颗n个点n-1条边的树,问选择本没有边相连的两个点,使得将这两个点相连能够构成二分图,一共有多少种选择方案

判断一个图是否是二分图可以用染色法:一共有两种颜色,每个点和它的相邻节点颜色不相同,看是否可以染色成功,如果可以,则是二分图,否则不是

1、暴力做法可以骗到19分

枚举每两个点,如果这两个点之间没有边,则尝试往这两条边之间连一条边,如果连边之后是一个二分图的话,答案就加一

 暴力C++代码如下:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1000010;
  4. vector<int> s[N];
  5. typedef pair<int,int> PII;
  6. map<PII,int> mp;
  7. int color[N];
  8. int dfs(int u,int c){//染色法判定二分图,颜色编号为1和2
  9. color[u]=c;
  10. for(int i=0;i<s[u].size();i++){//遍历u的所有邻点
  11. int j=s[u][i];
  12. if(!color[j]){//如果未被染色且染色失败,则返回false
  13. if(!dfs(j,3-c))return false;
  14. }else if(color[j]==c)//如果已经被染色但是颜色和u相同,也返回false
  15. return false;
  16. }
  17. return true;//染色成功,返回true
  18. }
  19. int main(){
  20. int n;
  21. cin>>n;
  22. for(int i=0;i<n-1;i++){
  23. int a,b;
  24. cin>>a>>b;
  25. s[a].push_back(b);
  26. s[b].push_back(a);
  27. mp[{a,b}]++;
  28. mp[{b,a}]++;
  29. }
  30. int sum=0;
  31. for(int i=1;i<=n;i++)
  32. for(int j=i+1;j<=n;j++)
  33. if(!mp[{i,j}]){//如果树中没有这条边,则加上这条边判断是否是二分图
  34. memset(color,0,sizeof color);
  35. s[i].push_back(j);
  36. s[j].push_back(i);
  37. if(dfs(i,1))sum++;
  38. s[i].pop_back();
  39. s[j].pop_back();
  40. }
  41. cout<<sum<<endl;
  42. return 0;
  43. }

二分图:图中不含有奇数环

正解:由于给定的树是一颗n个点n-1条边的树,所以一定是一个二分图,因为没有环

所以可以先给树中所有节点染色,然后算出两种颜色各含有多少节点

颜色编号为1的节点个数为x

颜色编号为2的节点个数为y,y=n-x

如果让所有颜色不同的点之间都有边也不会影响该二分图,所以一共有x*y种情况,但由于树中一开始就有n-1条边,所以二者之差就是答案,即x*y-(n-1)

 C++代码如下:

  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. const int N=1000010;
  5. typedef long long LL;
  6. vector<int> s[N];
  7. int color[N];//颜色编号为1和2
  8. void dfs(int u,int c){
  9. color[u]=c;
  10. for(int i=0;i<s[u].size();i++){
  11. int j=s[u][i];
  12. if(!color[j])//如果未被染色就染色
  13. dfs(j,3-c);
  14. }
  15. }
  16. int main(){
  17. int n,x=0,y=0;//x存储颜色为1的节点数,y存储颜色为2的节点数
  18. cin>>n;
  19. for(int i=0;i<n-1;i++){
  20. int a,b;
  21. cin>>a>>b;
  22. //添加一条无向边
  23. s[a].push_back(b);
  24. s[b].push_back(a);
  25. }
  26. dfs(1,1);//染色,该题一定会染色成功
  27. for(int i=1;i<=n;i++)
  28. if(color[i]==1)x++;
  29. y=n-x;
  30. cout<<(LL)x*y-(n-1)<<endl;
  31. return 0;
  32. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/864237
推荐阅读
相关标签
  

闽ICP备14008679号