小黄的刷题之路(十六)——五行魔法(枚举/蛮力法)

一、题目

在这里插入图片描述

在这里插入图片描述


二、分析思路

2.1 审题理解

  • 每一块五行石都有金木水火土五种能量(0表示没有对应属性的能量),施展魔法需要规定的五行能量,所以需要在给定的五行石里进行挑选,让其恰好满足施展魔法的要求
  • 一共有n块五行石,每一块都有被选中和没有被选中两种可能性,给出一个满足条件的方案,这是不是很眼熟呀,这不就是典型的0-1背包问题

2.2 思路

对于0-1背包问题,有很多种求解方法:分治法、回溯法、分支限界法、动态规划法、蛮力法

仔细一看题目,哎,五行石最多也就16块嘛,也不多,如果用蛮力法的话,考虑的情况有 2 16 2^{16} 216种,还行(好吧主要是我想偷懒)那就直接试试蛮力法吧(而且题目提示相关知识点是算法基础中的枚举),每一块五行石都有选和不选两种情况,对于n块五行石,就有 2 n 2^n 2n种方案,遍历每一种方案,直到找到满足要求的方案

这里以题目举例,n=4,四块五行石的五行能量分别如下,分割线下面一行是施展五行魔法所需要的能量(ABCDE分别代表是需要多少金木水火土能量)

A B C D E
1 0 0 0 0
1 0 0 0 0
0 1 0 0 0
0 0 1 1 1
-----------
1 1 1 1 1

四块五行石都有选和不选的可能,所以一共有 2 4 = 16 2^4=16 24=16种选择的方案,其中有至少一种满足要求的选择方案,既然是蛮力法,那就把所有方案试一遍,直到能量恰好能够施展魔法。背包问题里我们用1表示选中,0表示不选。现在有16种情况,而恰好0~15的二进制数 0000 , 0001 , . . . , 1111 0000,0001,...,1111 0000,0001,...,1111就表示了所有方案的选择。

遍历每一种方案将所有被选中的五行石的五种能量加起来,和所需的能量ABCDE做比较,如果不是恰好相等,那就下一个方案;如果刚好相等那就直接结束并输出该选择方案

注:题目要求如果有多种方案,就输出字典序最小的那个方案。而我们从0000遍历到1111,第一个满足的方案恰好就是所有可能方案字典序最小的那个,所以刚刚好直接输出就行。


三、代码实现

3.1. C++实现

#include<bits/stdc++.h> 
using namespace std;
int main( ){
    int n;
    cin>>n;
    int a[17][6],b[6];
    for(int i=1;i<=n;i++)
        cin>>a[i][1]>>a[i][2]>>a[i][3]>>a[i][4]>>a[i][5];

    cin>>b[1]>>b[2]>>b[3]>>b[4]>>b[5];
    //穷举法/蛮力法
    for(int i=0;i<(1<<n);i++)//穷举每一种选择方案
    {
        int s[6]={0};//用来累加当前方案的能量
        for(int k=1;k<=n;k++)
            if(i&(1<<(k-1)))//判断第k块石头是否被选中
                for(int j=1;j<=5;j++)s[j]+=a[k][j];
        bool flag=true;
        for(int j=1;j<=5;++j)//判断是否符合施展魔法的要求
            if(s[j]!=b[j])flag=false;
        
        if(flag)//第一个满足的方案恰好字典序最小
        {
            for(int k=1;k<=n;k++)
                if(i&(1<<(k-1)))cout<<k<<" ";
            break;
        }
    }
    return 0;
}

四、总结

  • 说实话这道题如果n的范围大一点,可能就无法通过测试了,但学会审题偷懒也是一种本事嘛(bushi)不过题目提示知识点是枚举,我觉得应该就是得用穷举吧
  • 此外,比较巧妙的是遍历的顺序,就刚好能让找到的第一个满足的方案恰好字典序最小,我们直接输出就好
  • 给我最大的启发还是善用位移运算符和逻辑运算符可以节省很多的时间

⭐感谢您能看到这里,这是对我莫大的鼓励!⭐

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值