一:概念
蛮力法是一种简单直接地解决问题的方法,常常直接基于问题的描述和所涉及的概念定义
二:优缺点
- 蛮力法适应能力强,是唯一一种几乎什么问题都能解决的一般性方法。
- 蛮力法一般容易实现,在问题规模不大的情况下,蛮力法能够快速给出一种可接受速度下的求解方法.
- 虽然通常情况下蛮力法效率很低,但可以作为衡量同类问题更高效算法的准绳
三: 算法案例
(1)枚举算法
- 百钱白鸡
-
问题构造
如何用100元买100只鸡?鸡翁1:值钱5; 鸡母1:值钱3; 鸡仔3:值钱1. -
问题分析:
用100元恰好买100只鸡;设x,y,z表示公鸡,母鸡,鸡仔数量;只有当z值被3整除时,解才可能有意义。 -
约束条件
0<=x<=100/5;
0<=y<=100/3;
0<=z<=100*3;
x+y+z=100;
5x+3y+z/3=100. -
完整的程序
-
#include "stdafx.h"
#include "stdio.h"
int main()
{
int x, y, z, i, j, k, flag = 0;
x = 5, y = 3, z = 3;//x为公鸡价格,y为母鸡价格,z为1元钱购买的鸡仔数量
for (i = 0; i <= 100 / x; i++)
for (j = 0; j <= 100 / y; j++)
for (k = 0; k <= 100 * z; k++)
{
if (i + j + k == 100 && i*x + j*y + k / z == 100 &&
k%z == 0)//判断购买公鸡,母鸡,鸡仔的数量与价格是否为100,且鸡仔的数量为3的整数倍
{
flag = 1;
printf("购买公鸡,母鸡,鸡仔的数量分别为%d %d %d \n", i, j, k);
}
}
if (flag == 0)
printf("no solution!\n");
}
- 0-1背包问题
- 问题构造
给定n种物品和一个背包。物品i的重量是Wi,其价值为Vi,背包的容量为C。应如何选择装入背包的物品,使得装入背包中的物品重量在不超过C的前提,总价值最大?附加条件:在选择装入背包的物品时,对每种物品i只有2种选择,即装入背包或不装入背包(1或0)。每种物品只有一份,不能将物品i装入背包多次,也不能将物品i装入背包多次,也不能将物品i分割只装入其的一部分。、 - 问题分析
背包问题的蛮力解法是穷举这些物品的所有子集,找出能够装到背包中的所有子集,并在这些子集中找出价值最大的子集。 - 完整程序
- 问题构造
#include "stdafx.h"
//背包问题:蛮力法
#include <iostream>
#include <cstdio>
#define maxx 9999
using namespace std;
int n;//货物的总个数
int weight;//背包承受上限
int value = 0;//最大价值
int sum_w = 0;//重量
int sum_v = 0;//价值
int r[maxx];//存储子集
int count;
struct node {
int weight;//重量
int value;//价值
bool flag = false;//标记是否被挑选
};
node pack[maxx];
int recursion(int x)
{
int count;
//判断重量是否超过背包承受上限
if (sum_w > weight)
{
return 0;
}
//判断最大价值
if (sum_v > value)
{
value = sum_v;
count = 0;
//将最大价值所对应的子集放入r中
for (int i = 0; i<n; i++)
{
if (pack[i].flag)
{
r[count++] = i;
}
}
}
for (int i = x; i<n; i++)
{
sum_v += pack[i].value;
sum_w += pack[i].weight;
pack[i].flag = true;
recursion(i + 1);
//回溯
sum_v -= pack[i].value;
sum_w -= pack[i].weight;
pack[i].flag = false;
}
}
int main()
{
cout << "请输入货物的总数量以及背包能承受的最大重量:" << endl;
cin >> n >> weight;
cout << "请依次输入每件物品的重量和价值:" << endl;
for (int i = 0; i<n; i++)
{
cin >> pack[i].weight >> pack[i].value;
}
recursion(0);
cout << "最大总价值的子集为: ";
for (int i = 0; i<count; i++)
{
cout << r[i] + 1 << " ";
}
cout << endl << "最大总价值最大可以为: " << value << endl;
return 0;
}
- 狱史问题
-
问题构造
国王对囚犯进行大赦,游戏规则是:让一个狱吏n次通过一排锁着的牢房,每通过一次,按规则转动n间牢房中某些门锁,每转一次,原来锁着的被打开,原来开着的被锁上;通过n次后,门锁开着的牢房中的犯人获得释放。
规则:1.每一次通过时:每间房门锁被打开;
2.第二次通过时:从第二间开始转动,每隔1间转动一次
3.第三次通过时:从第三间开始转动,每隔2间转动一次
……
k.第k次通过时:从第k间开始转动,每隔k-1间转动一次 -
问题分析
第1次转动门锁房号;1,2,…,n
第2次转动门锁房号;2,4,6,…
第3次转动门锁房号;3,6,9,…
……
第i次转动门锁房号;i,2i,3i,…
即:它们是起点为i,公差为i的等差数列。最后一次只转动第n号门锁一次。 -
设计思想
(1) 数组元素a[i](i=1,2,…,n)的初值均为1表示所有门锁着,门号与锁号相同。a[j]为0时表示锁号为j的锁开着。
(2) 当第j号门锁被转动时,a[j]=1-a[j]
(3) 每趟用i表示,1<=i<=n
(4) 每趟从第j个(j=i)锁开起,每隔i个锁转动一次,表示为j=j+I,i<=j<=n
例如:当a[j]=1时,则a[j]=1-a[j]=1-1=0;
当a[j]=0时,则a[j]=1-a[j]=1-0=1;- 完整代码
-
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#define maxn 32767
void main(void) {
int a[maxn];
int i, j, n;
printf("请输入牢房数量:");
scanf_s("%d", &n);
for (i = 0; i < n; i++)
a[i] = 1;
for (i = 1; i < n; i++)
for (j = i; j <= n; j += i + 1)
a[j] ^= 1;
for (i = 0; i < n; i++)
if (a[i])
printf("牢房号为%d的囚犯将获得释放 \n", i + 1);
printf("\n");
system("pause");
}