算法设计与分析

输油管道

在这里插入图片描述
在这里插入图片描述

分治–棋盘覆盖问题

详解PPT:https://wenku.baidu.com/view/e331f06c336c1eb91a375d75.html
详解博客:https://blog.csdn.net/sunshine__0411/article/details/78413823

#include<iostream>
using namespace std;

int tile=1;
int board[101][101]={0};
void chessBoard(int tr,int tc,int dr,int dc,int size)
{
	//tr、tc:棋盘左上角行号、列号
	//dr、dc:特殊方格所在行号
	//size:2^k,棋盘规格=2^k * 2^k 
	 
	if(size==1)
		return;
	int t=tile++;
	int s=size/2;
	
	/*
	左上棋盘(dr<tr+s&&dc<tc+s)的右下角方格board[tr+s-1][tc+s-1]
	右上棋盘(dr<tr+s&&dc>=tc+s)的左下角方格board[tr+s-1][tc+s]
	右下棋盘(dr>=tr+s&&dc>=tc+s)的左上角方格board[tr+s][tc+s]
	左下棋盘(dr>=tr+s&&dc<tc+s)的右上角方格board[tr+s][tc+s-1]
	*/ 
	//左上角子棋盘,
	if(dr<tr+s&&dc<tc+s)
	{	//特殊方格在继续分,s=size/2 
		chessBoard(tr,tc,dr,dc,s);
	}
	else
	{	//无特殊方格 
		board[tr+s-1][tc+s-1]=t;//覆盖子棋盘右下角的一个方格 
		chessBoard(tr,tc,tr+s-1,tc+s-1,s);//覆盖该子棋盘的其余方格 
	}
	//右上角子棋盘 
	if(dr<tr+s&&dc>=tc+s)
	{	//特殊方格在此棋盘中:右上角棋盘的列发生变化 
		chessBoard(tr,tc+s,dr,dc,s);
	}
	else
	{	//此棋盘无特殊方格 
		board[tr+s-1][tc+s]=t;//覆盖该子棋盘的左下角一个方格 
		chessBoard(tr,tc+s,tr+s-1,tc+s,s);//覆盖该子棋盘的其余方格 
	}
	//左下角子棋盘 
	if(dr>=tr+s&&dc<tc+s)
	{	
		//特殊方格在此棋盘中 
		chessBoard(tr+s,tc,dr,dc,s);//对该子棋盘继续划分 
	}
	else
	{	
		//无特殊方格
		board[tr+s][tc+s-1]=t;//对左下棋盘的右上角方格进行覆盖 
		chessBoard(tr+s,tc,tr+s,tc+s-1,s);
	}
	//右下角子棋盘 
	if(dr>=tr+s&&dc>=tc+s)
	{	
		//特殊方格在此棋盘中 
		chessBoard(tr+s,tc+s,dr,dc,s);
	}
	else
	{
		//此棋盘无特殊方格 
		board[tr+s][tc+s]=t;//对右下角棋盘的左上角方格进行覆盖 
		chessBoard(tr+s,tc+s,tr+s,tc+s,s);
	}
}

int main()
{
	/*
	0 0 12 14 16
	1 2 4 举例理解极好 
	*/
	int tr, tc, dr, dc, size;
	cin>>dr>>dc>>size;
	//chessBoard(0,0,12,14,16);
	chessBoard(0, 0, dr, dc, size);
	cout<<tile<<endl;
	for(int i=0;i<size;i++){ //输出结果
        for(int j=0;j<size;j++){
            cout.width(5);
            cout<<board[i][j];
            if(j==size-1){
                cout<<endl<<endl;
            }
        }
    }
	return 0; 
}

01背包(可输出物品)

//背包问题
//配合这篇讲解 
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

#define N 10//N件宝贝上限 
#define C 50//C是背包的总capacity,上限 
int n,c; 

int main()
{
	int i=1;
	int j=1;
	int value[N+1];//价值?
	int weight[N+1];//重量?
	int f[N+1][C+1];//f[i][j]表示在背包容量为j的情况下,前i件宝贝的最大价值
	memset(value,0,sizeof(value));
	memset(weight,0,sizeof(weight));
	memset(f,0,sizeof(f));
	cout<<"请输入宝贝个数、背包容量:"<<endl;
	cin>>n>>c;
	cout<<"依次输入宝贝重量、宝贝价值:"<<endl;
	for(int i=1;i<=n;i++)
		cin>>weight[i]>>value[i];
		
	//外循环控制物品数量,确保每个物品都会被遍历到	
	for(int i=1;i<=n;i++)		
	{
		/*for(j=weight[i];j<=C;j++)		//内循环控制物品的重量,确保能够遍历出“以前每个物品放入时的最大价值f[i][j]”
		{
		intx=f[i-1][j];		//不放第i件物品
		inty=f[i-1][j-weight[i]]+value[i];		//放入第i件物品
		f[i][j]=max(x,y);
		}*/
		
		//内循环控制物品的重量,确保能够遍历出"以前每个物品放入时的最大价值f[i][j]"
		for(j=1;j<=c;j++)
		{
			//背包容量为j时,遍历物品集合,选取价值最大的情况 
			//递推关系式
			if(j<weight[i])
			{
				f[i][j]=f[i-1][j];
			}
			else
			{
				//放与不放,选取极大值 
				f[i][j]=max(f[i-1][j] , f[i-1][j-weight[i]]+value[i]);
			}
		}
	}
	//行=物品数量,列=背包容量 
	for(i=0;i<=n;i++)
	{
		for(j=0;j<=c;j++)
		{
			printf("%4d",f[i][j]);
		}
		cout<<endl;
	}
	cout<<endl<<"选取的最大价值是:"<<f[n][c]<<endl;
	cout<<"选取的物品如下:"<<endl;
	i=n,j=c;
	//逆推 
	while(i)
	{
		if(f[i][j]==(f[i-1][j-weight[i]]+value[i]))
		{
			cout<<"物品:"<<i<<":"<<"weight="<<weight[i]<<",value="<<value[i]<<endl;
			j-=weight[i];
		}
		i--;
	}
	cout<<endl;
	return 0;
}
/*
3 10
3 4
4 5
5 6

*/

01背包

#include <iostream>
#include <cstdio>
#include <cstdlib>
 
using namespace std;
 
const int MAXN = 100;
 
int main()
{
    int n, V;
    int f[MAXN][MAXN];
    int w[MAXN], p[MAXN];
 	//
	cout<<"输入物品个数n、背包总容量V"<<endl;
    while(cin>>n>>V)
    {
    	
        cout<<" *****"<<endl;
        if(n == 0 && V == 0)
            break;
        //初始化我的包包f、单个物品重量w、单个物品价值p
        for(int i = 0; i <= n; ++i)
        {
            w[i] = 0, p[i] = 0;
            for(int j = 0; j <= n; ++j)
            {
                f[i][j] = 0;
            }
        }
        //注意以下循环都是从1开始的
		 
        //输入n个物品的单个物品重量w、单个物品价值p
        cout<<"依次输入物品重量、物品价值,如:1 2"<<endl; 
        for(int i = 1; i <= n; ++i)
            cin>>w[i]>>p[i];
 		//挨个遍历n个物品 
        for(int i = 1; i <= n; ++i)
        {
            int v = 1;
            while(v < w[i])//判断每个物品选取与不选取的时候,都要从背包为空开始枚举
            {
            	//背包容量依次增大 
                f[i][v] = f[i-1][v];
                ++v;
            }
            //当背包容量刚好可以容纳某个物品时,进行放与不放的选择 
            for(v = w[i]; v <= V; ++v)
            	//第i件物品的放与不放进行最大价值的比较 
                f[i][v] = max(f[i-1][v], f[i-1][v-w[i]]+p[i]);
        }
        cout<<f[n][V]<<endl;
    }
    return 0;
}

贪心背包

#include<cstdio>
#include <iostream> 
#include<vector>
using namespace std;
int LEN; //定义全局变量

struct Element
{
	float w;
	float v;
	float per;
	int i;
};

void mergeSort(Element *d)
{
	Element temp;
	for(int i=0;i<LEN-1;++i)
	{
		for(int j=0;j<LEN-1-i;++j)
		{
			if(d[j].per<d[j+1].per)
			{
				temp=d[j];
				d[j]=d[j+1];
				d[j+1]=temp;
			}
		}
	}
}

float knapsack(float c,vector <float> weight,vector <float> value,float *x)
{
	int n=LEN;
	Element d[LEN]={0};
	int i;
	for(i=0;i<n;++i)
	{
		cout<<weight.at(i)<<"  "<<value.at(i)<<endl;
		d[i].w=weight.at(i);
		d[i].v=value.at(i);
		d[i].per=value.at(i)/weight.at(i);
		d[i].i=i;
	}
	mergeSort(d);
	float opt=0;
	for( i=0;i<n;++i)
		x[i]=0;
	for( i=0;i<n;++i)
	{
		if(d[i].w>c)
			break;
		x[d[i].i]=1;
		opt+=d[i].v;
		c-=d[i].w;
	}

	if(i<n)
	{
		x[d[i].i]=c/d[i].w;
		opt+=x[d[i].i]*d[i].v;
	}

	return opt;
}


int main()
{
	vector <float> weight; 
	vector <float> value; 
//	float w[LEN]={12.5,10,9,8,6,7,5,3,2.5,4.6};
//	float v[LEN]={10,9,8,6,3,4,5,3,1.2,2.2};

	float w,v=0;
	int bag_capacity=0;
	cout<<"请输入背包容量:";
	cin>>bag_capacity;
	cout<<"输入物品重量和价值,-1 -1退出!例如:15 12"<<endl;
//	while(w!=-1){
//		scanf("%f,%f",&w,&v);
//		weight.push_back(w);
//		value.push_back(v);
//	} 
	float ws[10]={12.5,10,9,8,6,7,5,3,2.5,4.6};
	float vs[10]={10,9,8,6,3,4,5,3,1.2,2.2};
	for(int i=0;i<10;i++){
		weight.push_back(ws[i]);
		value.push_back(vs[i]);
	}
	LEN = weight.size();
//	vector<float>::iterator it;
//	for(it=weight.begin();it!=weight.end();it++)
//    	cout<<*it<<endl;
	float choice[LEN]={0};
//	float x[LEN]={0};
    float opt=knapsack(bag_capacity,weight,value,choice);
//	printf("opt:%f\n",opt);
//	printf("x数组为:");
	for(int i=0;i<LEN;++i)
	{
		if(choice[i]>0){
			cout<<i<<"号"<<choice[i]<<"重量:"<<weight.at(i)*choice[i]<<"\t价值:"<<value.at(i)*choice[i]<<endl;
		}
//		printf("%f ",choice[i]);
	}
	putchar('\n');
	system("pause"); 
	return 0;
}

二分查找

快速排序

//https://blog.csdn.net/Pit3369/article/details/86301457,自己当时写的博客
import java.util.Scanner;

public class QuickSort {
	public static int partition(int[] array,int lo,int hi) {
		int pivot=array[lo];
		while(lo<hi) {
			while((lo<hi)&&(pivot<array[hi])) hi--;
			if(lo<hi)
				array[lo++]=array[hi];
			while((lo<hi)&&(pivot>array[lo])) lo++;
			if(lo<hi)
				array[hi--]=array[lo];
		}
		array[lo]=pivot;
		return lo;
	}
	
	public static void quickSort(int[] array,int low,int high) {
		if(low<high) {
			int m=partition(array,low,high);
			quickSort(array,low,m-1);
			quickSort(array, m+1, high);
		}
	}
	
	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int num;
		System.out.println("输入数组大小:");
		num=in.nextInt();
		int[] array=new int[num];
		for (int i = 0; i < num; i++) {
			int n=in.nextInt();
			array[i]=n;
		}
		long time1 = System.currentTimeMillis();
		quickSort(array,0,num-1);
		long time2 = System.currentTimeMillis();
		System.out.println("排序耗时:"+(time2-time1));
		for (int i : array) {
			System.out.print(i+" ");
		}
	}
}

走台阶

package chapter_1;
//走台阶
public class walk_the_steps {
	
	public static int JumpFloor(int target) {
		if(target==0)
			return 0;
		if(target==1)
			return 1;
		if(target==2)
			return 2;
		return JumpFloor(target-1)+JumpFloor(target-2);
	}
	public static int abnormal_JumpFloor(int target) {
		//变态跳楼梯
		//https://blog.csdn.net/Hackbuteer1/article/details/6686747
		if(target==1)
			return 1;
		if(target==2)
			return 2;
		return 2*abnormal_JumpFloor(target-1);
	}
	public static void main(String[] args) {
		int count=0;
		int i,j,k;
		int h=3;
		for(i=0;i<=h;i++)
			for(j=0;2*j<=h;j++)
				if((i+2*j)==h) {
					System.out.printf("i=%d,j=%d\n",i,j);
					count++;
				}
						
		System.out.println("找到"+count+"种方法!");
		
		System.out.println(JumpFloor(h));
	}
}

汉诺塔问题

package chapter_1;

import java.util.ArrayList;
import java.util.Scanner;

//汉诺塔问题
public class Hanoi {
	static int count=0;

	public static void move(int n,char P,char Q) {
		System.out.println("第"+(++count)+"次移动:把"+n+"号盘子从"+P+"--移动至-->"+Q);
		
	}
	public static void hanoi(int n,char A,char B,char C) {
		if(n>0) {
			hanoi(n-1,A,C,B);//递归,将A塔上1~n-1的圆盘移到B上,以C为辅助塔
			move(n,A,C);
			hanoi(n-1,B,A,C);//递归,把B塔上1~n-1的圆盘移到C上,以A为辅助塔
		}
	}
	public static void main(String[] args) {
		int disks;
		char A='A';
		char B='B';
		char C='C';
		
		Scanner in=new Scanner(System.in);
		System.out.println("汉诺塔共有多少层?input n");
		disks=in.nextInt();
		hanoi(disks,A,B,C);
		System.out.println("总共移动圆盘次数:"+count);
		in.close();
	}
}

整数划分问题

package chapter_1;
import java.util.Scanner;
/*
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1。
https://www.cnblogs.com/hoodlum1980/archive/2008/10/11/1308493.html
*/
public class Integer_division {
	static int[] array=new int[200];
	static int n=0;
	static int integer_division(int n,int m) {
		if(n==1||m==1) 
			return 1;	
		else if(n<m)
			return integer_division(n,n);
		else if(n==m)
			return integer_division(n,m-1)+1;
		
		else{
			return integer_division(n,m-1)+integer_division(n-m,m);
		}
	}
	public static void print(int sum,int index,int m) {
		if(sum>n)
			return ;
		if(sum==n) {
			for (int i = 0; i < index-1; i++) 
				System.out.print(array[i]+"+");
			System.out.println(array[index-1]);
		}
		
		else {
			for (int i = m; i >0; i--) {//注意此处for循环内:大至小 小至大 的区别。
				array[index]=i;
				sum+=i;
				print(sum,index+1,i);
				sum-=i;
			}
		}
	}
	
	public static void main(String[] args) {
		int m;
		System.out.println("请输入待划分数n、最大划分数m:");
		Scanner in =new Scanner(System.in);
		n=in.nextInt();
		m=in.nextInt();
		int count=integer_division(n,m);
		System.out.println(count+"种划分结果!");
		//划分总和sum、第index个划分数索引、最大划分数m
		print(0,0,m);
	}
}

统计数字问题

本着书本页码不会太大的小小懒惰思想,把页码定义为long类型。

package chapter_1;

import java.util.Arrays;
import java.util.Scanner;

//统计数字问题
/*
 * 本书的页码从自然数1开始顺序编码直到自然数n.
 * 书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0.
 * 例如,第6页用数字6表示,而不是06或006等.数字计数问题要求对给定书的总页码n,
 * 计算出书的全部页码中分别用到多少次数字0,1,2,…,9.
 */
public class statistical_figures {
	public static void main(String[] args) {
		long num = 0;
		Scanner in =new Scanner(System.in);
		num=in.nextLong();
		count_num(num);
		System.out.println(num);
	}
	public static void count_num(long num) {
		int[] nums = new int[10];
		while(num!=0) {
			nums[(int) (num%10)]++;
			num=num/10;
		}
		//Arrays.sort(nums);
		//System.out.println(Arrays.toString(nums));
		for (int i = 0; i < nums.length; i++) {
			if(nums[i]!=0)
				System.out.print(i+"出现了"+nums[i]+"次!");
				
		}
	}
}

全排列

设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=R-{ri}。
集合X中元素的全排列记为perm(X)。
(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列。

//参考:https://blog.csdn.net/lemon_tree12138/article/details/50986990
public class full_array {
	public static void swap(int[] array,int cursor,int i) {
		int temp1=array[cursor];
		int temp2=array[i];
		array[cursor]=temp2;
		array[i]=temp1;
	}
	public static void fullarray(int[] array,int cursor,int end) {
		if(cursor==end)
			System.out.println(Arrays.toString(array));
		else {
			for (int i = cursor; i <=end; i++) {
				swap(array,cursor,i);
				fullarray(array,cursor+1,end);
				//交换元素后,进行递归操作,但是在递归结束后,进行下一次循环时,数组已经被交换过一次,不是最原始的
				//所以在递归结束后,将数组还原,保持数组一致性
				swap(array,cursor,i);
			}
		}
	}
	
	public static void main(String[] args) {
		System.out.println("请输入集合大小及其集合:");
		
		
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int[] array = new int[n];
		int i=0;
		for (int j = 0; j < n; j++) {
			array[j]=in.nextInt();
		} 
		//System.out.println(Arrays.toString(array));
		fullarray(array,0,n-1);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值