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