算法详解(二):蛮力法

一:概念

蛮力法是一种简单直接地解决问题的方法,常常直接基于问题的描述和所涉及的概念定义

二:优缺点

  1. 蛮力法适应能力强,是唯一一种几乎什么问题都能解决的一般性方法。
  2. 蛮力法一般容易实现,在问题规模不大的情况下,蛮力法能够快速给出一种可接受速度下的求解方法.
  3. 虽然通常情况下蛮力法效率很低,但可以作为衡量同类问题更高效算法的准绳

三: 算法案例

(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");
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值