A-打怪
传送门:https://ac.nowcoder.com/acm/contest/5026/A
思路:首先可以自己先去模拟一下样例是怎样实现的,熟悉一下思路。然后,我们可以看到,我是先手,只有当我的血量为0的时候,游戏才结束。在看到题目给出的数据又不是很大,所以可以模拟出双方每次的血量变化量,然后一边记下少了几个怪即可。但是这里我们要到单独考虑哪些情况下是-1.显然,如果毛怪一下都打不到你的话,你的血量就一直不变,如果在杀死每个毛球怪的循环中,你会被毛怪攻击到,那么肯定有这么一个回合,你的血量会为0。想清楚了这点,就可以写出代码了。
代码+详细注释
#include<bits/stdc++.h> using namespace std; void solve(){ int pb,pa,gb,ga; //pb表示人的血量,pa表示人的攻击力,gb表示怪的血量,pa表示怪的攻击力 int ans=0; cin>>pb>>pa>>gb>>ga; if(gb<=pa) cout<<"-1"<<endl; //如果怪连人的第一个回合都扛不住的话,那么说明人就得了永生 else{ //否则 int temp=gb; //先将怪的初始血量存下 while(pb>0){ //在人的血量大于0的情况下 gb-=pa; //怪的血量先减 if(gb<=0){ //怪被打死的情况 ans++; gb=temp; //恢复成下一个怪的初始血量 } else pb-=ga; //如果怪没被打死的话,说明它可以攻击人 } cout<<ans<<endl; } } int main(){ int t; cin>>t; while(t--){ solve(); } return 0; }
B 吃水果
传送门:https://ac.nowcoder.com/acm/contest/5026/B
思路:贪心+模拟,首先,你还是可以先进行一些模拟,寻找到一些规律来。然后,为了方便,我们先进行一些处理让n是m和n当中更小的那个。如果,m==n的话,那么直接输出答案即可,否则,n就是更小的那个,m就是更大的那个。我们可以看到,这个数据范围还是比较小,因此可以用第一题的思路,依然用循环,模拟出每一步的情况,在进行处理即可。
我们可以看到,在n,m都不为0的情况下,如果,m大于n的两倍的话,例如n=2,m=7,那么最好的办法就是将n进行翻倍,如果m在n的1-2倍之间的话,那么此时的最优解就是吃一个苹果和香蕉。如果n==m的话,那么可以直接得到当前的ans+n就是最终答案了。
代码+详细注释
#include<bits/stdc++.h> using namespace std; void solve(){ int n,m; cin>>n>>m; int ans=0; if(n>m) swap(n,m); //认为规定n要小于m if(n==m) cout<<n<<endl; else{ while(n!=0&&m!=0){ while(n*2<=m){ //如果m超过了n的2倍 ans++; n*=2; //n翻倍 } if(n==m){ //n==m的话,ans+n跳出 ans+=n; n=m=0; } else if(m/n==1){ //如果,m在n的1-2倍之间 n--,m--; //同时-1 ans++; } } cout<<ans<<endl; } } int main(){ int t; cin>>t; while(t--){ solve(); } return 0; }
C题 四个选项
传送门:https://ac.nowcoder.com/acm/contest/5026/C
思路:并查集+dfs,在做这题的时候,想得到是dfs,但是就是还没有接触到并查集,所以卡在了如何进行分组的地方了。事后赶紧补上。还是那样,可以看到,这题的数据还是不算大,因此可以现根据条件进行一些分组,显然是将选项一样的分为同一组,确保哪几个题的选项要是一致的。
首先,我对输入的数据进行处理,根据限制条件进行适当的分组,这里用的就是并查集用法,当然,这里不用路径压缩也行。复杂度完全是够的。并查集的知识点就不再这里做展开了,可以自行bing。我们重点来介绍一下用dfs怎样进行实现的。首先,我们将有5个参数为l,a,b,c,d,l表示的是你一共确定了几道题的选项,后面4个参数分别是当前的a,b,c,d四个选项的个数有多少。
void dfs(int l,int a,int b,int c,int d){ if(l==12){ //递归结束的条件 int i; if(na!=a||nb!=b||nc!=c||nd!=d) return; //如果这种情况下的a,b,c,d的个数不符合题目的要求,直接退出 //接下来就是对那些m个限制条件进行处理了 for(i=1;i<=12;i++){ //检查一下每一题的选项 if(t[i]!=t[v[i]]) break; //如果这种情况的分配下,其中某两题的选项不一样,但是题目的要求有要是一样,说明这种情况不符合。 } if(i<=12) return; //不符合的情况 ans++; //既满足大条件,又满足限制的条件,哪这种情况就可以 return; } //每个题目有下面4个选项可以选择,分别查找即可 t[l+1]=1,dfs(l+1,a+1,b,c,d); //以此为当前的题目选a,b,c,d对应1,2,3,4,其中t[i]表示第i个题目的选项是1,2,3,4中的哪一个 t[l+1]=2,dfs(l+1,a,b+1,c,d); t[l+1]=3,dfs(l+1,a,b,c+1,d); t[l+1]=4,dfs(l+1,a,b,c,d+1); }
代码+详细注释
#include<bits/stdc++.h> using namespace std; int na,nb,nc,nd,m,ans; int v[20],t[20]; int find(int x){ //并查集查找根节点 if(x==v[x]) return x; return v[x]=find(v[x]); } void dfs(int l,int a,int b,int c,int d){ if(l==12){ //递归结束的条件 int i; if(na!=a||nb!=b||nc!=c||nd!=d) return; //如果这种情况下的a,b,c,d的个数不符合题目的要求,直接退出 //接下来就是对那些m个限制条件进行处理了 for(i=1;i<=12;i++){ //检查一下每一题的选项 if(t[i]!=t[v[i]]) break; //如果这个选项不属于 } if(i<=12) return; ans++; return; } //每个题目有下面4个选项可以选择,分别查找即可 t[l+1]=1,dfs(l+1,a+1,b,c,d); //以此为当前的题目选a,b,c,d t[l+1]=2,dfs(l+1,a,b+1,c,d); t[l+1]=3,dfs(l+1,a,b,c+1,d); t[l+1]=4,dfs(l+1,a,b,c,d+1); } int main(){ cin>>na>>nb>>nc>>nd>>m; for(int i=1;i<=12;i++) v[i]=i; //先将每个数据的根节点设为自己 int i,j,x,y; while(m--){ cin>>x>>y; i=find(x),j=find(y); //查找根节点来确定他们是否为同一组的 if(i!=j) v[i]=j; //如果x,y的根节点不一样的话,但是题目要求的又是他们选项要一致, //所以可以将其中一个的根节点设为另一个的根节点 } dfs(0,0,0,0,0); cout<<ans<<endl; return 0; }