蛮力法的相关问题总结

今天想写写关于蛮力法的一些问题,也给之后自己留下一个笔记。
蛮力法关键------依次处理所有元素

1.查找问题中的蛮力法

  • 顺序查找
int SeqSearch(int r[],int n,int k)
{
i=n;
while(i>0&&r[i]!=k)
     i--;
   return i;
}

上述算法基本语句是i>0和r[i]!=k,其执行次数为:
O(n)
改进的顺序查找
将带查找值放在查找方向的尽头处,免去在查找过程中每一次比较后都要判断查找位置是否越界,从而提高查找速度。

int SeqSearch(int r[],int n,int k)
{
r[0]=k;i=n;
while(r[i]!=k)
     i--;
   return i;
}

此算法的基本语句是r[i]!=k,其执行次数为:(n+1)/2
O(n)数量级相同,系数相差一半

  • 串匹配问题
//文本 T[0...n-1]长度为n
//模式P[0....m-1]长度为m
//查找不成功返回-1
forint i=0;i<=n-m;i++{
      j=0;
  while(j<m&&P[j]==T[i+j])
       j++;
 if(i==m)
    return i;
  return -1;
}

考虑最坏的情况,每趟不成功匹配都发生在串T的最后一个字符,在(i-1)趟不成功的匹配中共比较了(i-1)m次,第i趟成功的匹配共比较了m次,所以总共比较了im 次,因此平均比较次数是:m(n-m+2)/2

2.排序问题中的蛮力法

  1. 选择排序
void SelectSort(int r[],int n){
   for(int i=0;i<n-1;i++){
      index=i;
      for(j=i+1;j<=n;j++)
      if(r[j]<r[index])
      index=j;
      if(index!=i)
         r[i]------r[index]   //交换这两的元素位置
    }
}

基本语句是内层循环体中的比较语句r[j]<r[index],执行次数n(n-1)/2,O(n^2)
3. 冒泡排序

void Sort(int r[],int n){
  for(i=1;i<=n-1;i++){
    for(j=1;j<=n-i;j++)
       if(r[j]>r[j+1])
          r[j]----r[j+1]  //交换元素
   }
}

组合问题中的蛮力法

  1. 生成排列对象
    用蛮力法生成{1,2…,n}的所有n!个排列。

例:

开始 1

插入 2 12 21

插入3 123 132 312 213 231 321

//伪代码:
//先生成初始排列{1};
 for(i=2;i<=n;i++)
   for(j=1;j<=(i-1)!;j++)
        for(k=i;k>=1;k--)
           将i插入到第j个排列中的第k个位置;

借鉴代码https://blog.csdn.net/wlk1229/article/details/7596837

/*蛮力法解决全排列问题*/
#include<iostream>
#include<string>
using namespace std;
 
 
void insert(char c1[], char c2[], char c, int i)
//将c 插入c1 并将c1复制到c2
{
	int j;
	for (j = 0; j < i; j++)
		c2[j] = c1[j];
	c2[i] = c;
	for (j = i + 1; j <= strlen(c1) + 1; j++)
		c2[j] = c1[j - 1];
}
 
 
void perml(int n)//为生成排列集合元素的个数
{
	int i, j, k, m = 1;
 
 
	char **c[2];//采用两个字符序列存储,分别存储i-1和i的全排列
 
 
	c[1] = new char*[1];
	c[1][0] = new char[2];
	c[1][0][0] = '1'; c[1][0][1] = 0;
 
 
	for (i = 2; i <= n; i++)
	{
		m = m*(i - 1);
		c[i % 2] = new char*[m*i];
		for (j = 0; j < m; j++)
		{
			for (k = 0; k < i; k++)
			{
				c[i % 2][j*i + k] = new char[i + 1];
				insert(c[(i + 1) % 2][j], c[i % 2][j*i + k], char(i + '0'), k);
			}
			delete[] c[(i + 1) % 2][j];
		}
		delete[] c[(i + 1) % 2];
	}
	for (i = 0; i < m*n; i++)
	{
		cout << "第" << i + 1 << "排列:" << c[n % 2][i] << endl;
		delete[] c[n % 2][i];
	}
}
 
 
int main()
{
	perml(3);
	return 0;
}

  1. 生成子集
    字典序
list_1=[]
list_2=[]
answer=[]
n=int(input("input:"))
for i in range(0,n):
    list_1.append(input("input:"))
    list_2.append(0)
sum1=0
i=n-1
print(answer)
while sum1<n:
    i=n-1
    if list_2[i]==0:
            list_2[i]=1
    else:
        list_2[i]=0
        while i>0:
            if list_2[i-1]==1:
                list_2[i-1]=0
                i=i-1
            else:
                list_2[i-1]=1
                break
    sum1=sum(list_2)
    for i in range(0,n):
        if list_2[i]==1:
            answer.append(list_1[i])
    print(answer)
    answer.clear()
  1. 0/1背包问题
    用蛮力法解决0/1背包问题,需要考虑给定的n个物品集合的所有子集,找出所有可能的子集,计算每个子集的总价值,然后在他们中找到价值最大的子集。对于一个具有n个元度的集合,其子集的数量是2^n,所以无论生成子集的算法效率有多高,蛮力法都会导致一个2的n次方的算法。
    自己写的有点糙,还是根据上面那个代码改进着来的
list_weight=[]
list_vlaue=[]
list_2=[]
maxweight=int(input("输入背包最大容量:"))
n=int(input("input n:"))
for i in range(0,n):
    list_weight.append(int(input("输入第"+str(i+1)+"件物品的重量:")))
    list_vlaue.append(int(input("输入第"+str(i+1)+"件物品的价值:")))
    list_2.append(0)
sum1=0
sumw=0
sumv=0
i=n-1
while sum1<n:
    i=n-1
    sw=0
    sv=0
    if list_2[i]==0:
            list_2[i]=1
    else:
        list_2[i]=0
        while i>0:
            if list_2[i-1]==1:
                list_2[i-1]=0
                i=i-1
            else:
                list_2[i-1]=1
                break
    sum1=sum(list_2)
    for i in range(0,n):
        if list_2[i]==1:
            sw=sw+list_weight[i]
            sv=sv+list_vlaue[i]
    if sw<maxweight and sv>sumv:
        sumw=sw
        sumv=sv

print(sumv)
  • 任务分配问题
    假设有n个任务需要分配给n个人执行,每个任务只分配给一个人,每个人只分配一个任务,且第j个任务分配给第i个人的成本是C [ i, j ]1<=i,j<=n),任务分配问题要求找出总成本最小的分配方案。

图问题中的蛮力法

  • 哈密顿回路问题
    对给定的无向图G=(V,E),首先生成图中所有的顶点的排列对象(vi1,vi2,)然后依次考察每个排列对象是否满足一下两个条件:1.相邻顶点之间存在边;2.最后一个顶点和第一个顶点之间存在边 满足这俩条件的回路就是哈密顿回路。
    考察所有点的排列对象,O(n!)

  • TSP问题
    旅行家要旅行n个城市然后回到出发城市,要求各个城市经历且经历一次,并要求所走的路程最短。用蛮力法解决,找出所有可能的旅行路线,从中选取路径长度最短的简单回路。

几何问题中的蛮力法

  • 最近对问题
    最近对问题要求找出一个包含n个点的集合中距离最近的两个点;蛮力法求解是分别计算呢每一对点之间的距离,然后找出距离最小的那一对,为了避免对同一对点计算两次距离,只考虑i<j的那些点对(pi,pj)
    大致思路如下 O(n^2)
int ClosesPoints(int n,int x=[],int y[],int &index1,int &index2){
      minDist=无穷大
      for(int i=1;i<n;i++)
      for(int j=i+1;j<n;j++)
        {
            d=(x[i]-x[j])^2+(y[i]-y[j])^2;
            if(d<minDist)
              {  minDist=d;
                  index1=i;
                  index2=j;
              }
         }
return minDist;
}
  • 凸包问题
    一个点集S的凸包是包含S的最小凸集合,其中,最小是指S的凸包一定是所有包含S的凸集合的子集,对于平面上的n个点的集合S,他的凸包就是包含所有这些点的最小凸多边形。蛮力法解决凸包问题的基本思想:对于一个由n 个点构成的集合S中的两个点P1和P2,当且仅当该集合中的其他点都位于穿过这两点的直线的同一边时,他们的连线就是该集合凸包边界的一部分。对每一对顶点都检验一遍之后,免租条件的线段构成了该凸包的边界。
    在平面上 穿过两点的直线是 ax+by=c (a=y2-y1,b=x1-x2,c=x1y2-x2y1)
    这条线吧平面分成零分半平面,其中一个的点满足 ax+by>c
    另一个ax+by<c
    时间复杂性是O(n的 三次方)
    步骤:
    将点集里面的所有点两两配对,组成 n(n-1)/2 条直线。
    对于每条直线,再检查剩余的 (n-2) 个点是否在直线的同一侧。
    如何判断一个点 p3 是在直线 p1p2 的左边还是右边呢?(坐标:p1(x1,y1),p2(x2,y2),p3(x3,y3)) ???
    https://blog.csdn.net/u011001084/article/details/72768075
    借鉴某一大佬写的可视化版本凸包问题
import random
import matplotlib.pyplot as p

input = int(input('输入生成点的数量:'))
dot = [[0] * 3 for i in range(input)]
x = [[0] * 2 for a in range(int(input * (input - 1) / 2))]
y = [[0] * 2 for b in range(int(input * (input - 1) / 2))]
fg = p.figure()
cn = fg.add_subplot(1, 1, 1)
cn.set_xlim(0, 1000)
cn.set_ylim(0, 1000)
p.ion()
for i in range(input):
    dot[i][0] = random.randrange(1000)
    dot[i][1] = random.randrange(1000)
    dot[i][2] = 0


def judge(inp):
    n = 0
    for i in range(inp):
        for j in range(i + 1, inp):
            a = dot[j][1] - dot[i][1]
            b = dot[i][0] - dot[j][0]
            c = (dot[i][0] * dot[j][1]) - (dot[i][1] * dot[j][0])
            sign1 = 0
            sign2 = 0
            x[n][0] = dot[i][0]
            x[n][1] = dot[j][0]
            y[n][0] = dot[i][1]
            y[n][1] = dot[j][1]
            n += 1
            for k in range(inp):
                if k == j or k == i:
                    continue
                if a * dot[k][0] + b * dot[k][1] == c:
                    sign1 += 1
                    sign2 += 1
                if a * dot[k][0] + b * dot[k][1] > c:
                    sign1 += 1
                if a * dot[k][0] + b * dot[k][1] < c:
                    sign2 += 1
                if (sign1 == (inp - 2)) or (sign2 == (inp - 2)):
                    dot[i][2] = 1
                    dot[j][2] = 1
                    cn.scatter(dot[i][0], dot[i][1], color='g', marker='.')
                    cn.scatter(dot[j][0], dot[j][1], color='g', marker='.')
                    cn.plot(x[n - 1], y[n - 1], color='b')
            cn.scatter(dot[i][0], dot[i][1], color='g', marker='.')
            cn.scatter(dot[j][0], dot[j][1], color='g', marker='.')
            cn.plot(x[n - 1], y[n - 1], color='r')
            p.pause(0.1)
            cn.lines.pop()


judge(input)
print("凸包极点:")
for i in range(input):
    if dot[i][2] == 1:
        print((dot[i][0], dot[i][1]))
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值