算法设计与分析前六章

算法概述

算法的概念: 算法是指解决问题的一种方法或一个过程,更严格地讲,算法是由若干条指令组成的有穷序列。

算法的概念、特征、表达、设计过程

程序的概念:程序是算法用某种程序设计语言的具体实现,程序可以不满足算法的有限性。

算法+数据结构=程序 ->算法是程序的灵魂。


程序设计:行为设计+结构设计。
行为设计:其结果是算法
结构设计:对要解决的问题定义数据结构 (包括物理结构和逻辑结构)

时间复杂度计算

主定理

递归树

借助树来求解递归算法的时间复杂度

递归与分治策略

算法设计第二章总结

常见的7种排序算法

快速幂算法

#include<iostream>

using namespace std;

int fast_pow(int x,int y)
{
		int temp;
		if(y==1) return x;
		else if((int)y%2==0){
			temp=fast_pow(x,y/2);
			return temp*temp;
		}
		else{
			temp=fast_pow(x,(y-1)/2);
			return temp*temp*x;
		}
}

int main()
{
	float x;//底数 
	float y;//指数
	float result;
	
	cin>>x>>y;
	result=fast_pow(x,y);
	cout<<result<<endl;
	
	return 0; 
 } 

棋盘覆盖问题

动态规划

算法设计与分析第三章:动态规划

矩阵连乘问题

#include<iostream>
#define MAX 10050
using namespace std;

void Strassen_m(int *r,int n,int **stra,int **fl)
{
	for(int i=1;i<=n;i++) stra[i][i]=0;
	for(int p=2;p<=n;p++)
		for(int i=1;i<=n-p+1;i++)
		{
			int j=i+p-1;
			stra[i][j]=stra[i+1][j]+r[i-1]*r[i]*r[j];
			fl[i][j]=i;
			for(int k=i+1;k<j;k++){
				int temp=stra[i][k]+stra[k+1][j]+r[i-1]*r[k]*r[j];
				if(temp<stra[i][j]){
					stra[i][j]=temp;
					fl[i][j]=k;
				}
			}
		}
}

void trace(int i,int j,int **fl)
{
	if(i==j){
		cout<<"A"<<i;	
	}
	else{
		cout<<"(";
		trace(i,fl[i][j],fl);
		trace(fl[i][j]+1,j,fl);
		cout<<")";
	}
	
	/*cout<<"multiply A"<<i<<","<<fl[i][j];
	cout<<" and A "<<(fl[i][j]+1)<<","<<j<<endl;*/
}
int main()
{
	int m;
	cin>>m;
	while(m--){
	int rr;
		int tmp=0;
		int r[MAX];
	while(cin>>rr){
		
		r[tmp]=rr;
		tmp++;
		if(cin.get()=='\n')
		break;
	}
	
	int **stra=new int *[tmp+1];
	stra[0]=new int[(tmp+1)*(tmp+1)];
	for(int i=1;i<tmp+1;i++)
		stra[i]=stra[i-1]+tmp+1;
	
	int **fl=new int *[tmp];
	fl[0]=new int[tmp*tmp];
	for(int i=1;i<tmp;i++){
		fl[i]=fl[i-1]+tmp;
	}	
	
	for(int i=1;i<=tmp-1;i++)
		for(int j=1;j<=tmp-1;j++)
			stra[i][j]=-1;
	
	Strassen_m(r,tmp-1,stra,fl);
	for(int i=1;i<=tmp-1;i++){
			for(int j=1;j<=tmp-1;j++)
			printf(" %d ",stra[i][j]);
			cout<<endl;
	} 
	for(int i=1;i<=tmp-1;i++){
		for(int j=1;j<=tmp-1;j++)
			printf(" %d ",fl[i][j]);
		cout<<endl;
	} 
	cout<<stra[1][tmp-1]<<endl;
	trace(1,tmp-1,fl);
	cout<<endl;
/*	for(int i = 0; i < tmp+1; i++){
        delete[] stra[i];  
    }
    delete[] stra;
  for(int i = 0; i < tmp; i++){
        delete[] fl[i];   
    }
    delete[] fl;*/
	} 
	return 0;
	
 } 

最长公共子序列(LCS)

#include<iostream>
#include<string>
#define MAX 10050
using namespace std;

void LCSlength(int l1,int l2,const string s1,const string s2,int **m)
{
	int i,j;
	for(i=0;i<l1+1;i++){
		m[i][0]=0;
	}
	for(j=1;j<l2+1;j++){
		m[0][j]=0;
	}
	for(i=1;i<l1+1;i++){
		for(j=1;j<l2+1;j++){
			if(s1[i-1]==s2[j-1]){
				m[i][j]=m[i-1][j-1]+1;
			}
			else{
				m[i][j]=max(m[i-1][j],m[i][j-1]);
			}
		}
	}
//	return m[l1][l2];			
}

void trace(int i,int j,string s1,int **m)
{
	if(i==0||j==0) return ;
	if(m[i][j]==m[i-1][j]){
		trace(i-1,j,s1,m);
	}
	else if(m[i][j]==m[i][j-1]){
		trace(i,j-1,s1,m);
	}
	else{
		trace(i-1,j-1,s1,m);
		cout<<s1[i-1];
	}
}
void printLCS(int **m,string s1,int i,int j)
{
	static char s[MAX];
	int k=m[i][j];
	s[k]='\0';
	while(k>0){
		if(m[i][j]==m[i-1][j]) i--;
		else if (m[i][j]==m[i][j-1]) j--;
		else {
			s[--k]=s1[i-1];
			i--,j--;
		}
	}
	printf("%s",s);
}
int main()
{
	int n;
	cin>>n;
	
	for(int k=1;k<=n;k++){
	
	string s1;
	string s2;
	cin>>s1>>s2;
    int l1=s1.length();
    int l2=s2.length();
    
    int **m= new int *[l1+1];
    m[0]=new int[(l2+1)*(l2+1)];
    for(int i=1;i<l1+1;i++){
    	m[i]=m[i-1]+l2+1;
	}
	
	LCSlength(l1,l2,s1,s2,m);
		for(int i=0;i<l1+1;i++){
			for(int j=0;j<l2+1;j++){
			cout<<m[i][j]<<' ';
		}
		cout<<endl;
	}
	trace(l1,l2,s1,m);
//	printLCS(m,s1,l1,l2);
	cout<<endl;
	
	}
	
	return 0;
}

01背包问题(通俗易懂,超基础讲解

总结——01背包问题 (动态规划算法)

#include<iostream>
#include<fstream>
#define MAX 10050
using namespace std;
int v[MAX];
int w[MAX];
int F[MAX][MAX]={{0}};
int item[MAX];
void findMAX(int n,int W){	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=W;j++){
			if(j<w[i])
				F[i][j]=F[i-1][j];
			else
				F[i][j]=max(F[i-1][j],F[i-1][j-w[i]]+v[i]);
		}
	}
}
void find(int i,int j){
	if(i>=0){
		if(F[i][j]==F[i-1][j]){
			item[i]=0;
			find(i-1,j);
		}
		else if((j-w[i])>=0&&F[i][j]==(F[i-1][j-w[i]]+v[i])){
			item[i]=1;
			find(i-1,j-w[i]);
		}
	}
	
}
int main()
{
	ifstream in("input.txt");
	
	int n,W;
	in>>n>>W;

	for(int i=1;i<=n;i++)
		in>>v[i];
	for(int i=1;i<=n;i++)
		in>>w[i];
	
	findMAX(n,W);
	find(n,W);
	for(int i=0;i<=n;i++){
		for(int j=0;j<=W;j++)
		printf("%4d",F[i][j]);
		cout<<endl;
	}
	for(int i=1;i<=n;i++)
	cout<<item[i]<<' ';	
	ofstream out("output.txt");
	out<<F[n][W]<<endl;
	for(int i=1;i<=n;i++)
	out<<item[i]<<' ';	
	
	in.close();
	out.close();
	return 0;
 } 

贪心算法

算法设计与分析第四章:贪心算法

活动安排问题

#include<iostream>
#include<algorithm>
using namespace std;

struct node{
	int st;
	int ft;
};
bool cmp(struct node x,struct node y){
	return x.st<y.st;
}
int main()
{
	int n;
	cin>>n;
	struct node act[n+1];
	for(int i=1;i<=n;i++){
		cin>>act[i].st;
		cin>>act[i].ft;
	}
	sort(act+1,act+n+1,cmp);
/*	for(int i=1;i<=n;i++){
		cout<<act[i].st<<' '<<act[i].ft<<endl;
	}*/
	int A[n+1]={0}; 
	int k=1;
	for(int i=1;i<=n;i++){
			if(A[i]==0) A[i]=k;
			else continue;
			int temp=i;
			for(int j=i+1;j<=n;j++){
				if((act[j].st>=act[temp].ft)&&A[j]==0){
					A[j]=k;
					temp=j;
					}
			}
			k++;
	}
	cout<<k-1<<endl;
	return 0;
} 

最优装载

最小生成树详解(模板 + 例题) 

最优子结构性质是指一个问题的最优解包含其子问题的最优解。在证明最优子结构性质时,通常需要使用归纳法或反证法。

归纳法证明最优子结构性质的步骤如下:

  1. 假设问题的最优解包含其子问题的最优解。
  2. 假设存在一个更优的解,该解不包含子问题的最优解。
  3. 通过比较两个解的值,证明假设的存在性是错误的。
  4. 根据归纳法的原理,可以得出结论:问题的最优解包含其子问题的最优解。

反证法证明最优子结构性质的步骤如下:

  1. 假设问题的最优解不包含其子问题的最优解。
  2. 通过比较两个解的值,证明假设的存在性是错误的。
  3. 根据反证法的原理,可以得出结论:问题的最优解包含其子问题的最优解。

通过以上的证明过程,可以得出结论:最优子结构性质成立。

贪心选择性质的证明是通过数学归纳法来完成的。首先,我们需要定义问题的最优解结构,并证明贪心选择性质成立。

  1. 定义问题的最优解结构:假设问题的最优解是S={a1, a2, …, ak},其中a1, a2, …, ak是问题的一个最优解的一部分。我们假设在S中存在一个非最优解S’={a1, a2, …, ak, ak+1},其中ak+1不是最优解的一部分。

  2. 证明贪心选择性质成立:我们需要证明,在S中存在一个贪心选择ak,使得S’={a1, a2, …, ak, ak+1}不是最优解。假设存在这样的贪心选择ak,那么我们可以将ak+1替换为ak,得到一个新的解S’'={a1, a2, …, ak},这个解比S更优。这与S是最优解的假设相矛盾。

  3. 通过数学归纳法证明贪心选择性质成立:我们可以通过数学归纳法来证明贪心选择性质成立。首先,我们证明问题的最优解结构中只包含一个元素的情况。然后,我们假设问题的最优解结构中包含k个元素,并证明在这个结构中存在一个贪心选择,使得结构中包含k+1个元素的解不是最优解。通过这样的归纳证明,我们可以得出贪心选择性质成立。

综上所述,贪心选择性质的证明是通过定义问题的最优解结构,并通过数学归纳法证明贪心选择性质成立。这样,我们可以通过贪心算法中的贪心选择来得到问题的最优解。

回溯算法

算法设计与分析第五章思维导图&&知识点总结

装载问题

回溯法之N皇后问题

#include<iostream>
#include<cmath> 
using namespace std;

class Queen{
		friend int nQueen(int);
	private:
		bool Place(int k);
		void Backtrace(int t);
		int n,*x;
		long sum;
};

bool Queen::Place(int k){
	for(int j=1;j<k;j++)
	{
		if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
			return false;
	}
	return true;
}
void Queen::Backtrace(int t)
{
	if(t>n){
		sum++;
		cout<<"No."<<sum<<endl;
		for(int i=1;i<=n;i++)
			cout<<i<<' '<<x[i]<<endl;
	}
	else{
		for(int i=1;i<=n;i++){
			x[t]=i;
			if(Place(t))
				Backtrace(t+1);
		}
	}
}
int nQueen(int n){
	Queen X;
	X.n=n;
	X.sum=0;
	int *p=new int[n+1];
	for(int i=0;i<=n;i++){
		p[i]=0;
	}
	X.x=p;
	X.Backtrace(1);
	delete[] p;
	return X.sum;
}
int main()
{
	int n;
	cin>>n;
	int nCount=nQueen(n);
	cout<<endl;
	cout<<nCount<<endl;
	return 0;
 } 

回溯法解01背包问题​ ​​​​​​ 

#include<iostream>
#include<algorithm>
#define MAX 10050
using namespace std;
int n;
int c;
int x[MAX]; 
int best_x[MAX];//最优情况 
int best_v;//最优价值 
int cv;//当前价值 
int cw;//当前已存质量 
struct node{
	int id;
	double w;
	double v;
	double vw;//性价比 
}item[MAX];

bool cmp(node x,node y){
	return x.vw>y.vw;
}

void print()
{
	for(int i=1;i<=n;i++){
		cout<<item[i].id<<":"<<item[i].vw<<endl;
	}
}

int bound(int i){
	int cleft=c-cw;//背包剩余容量 
	int value=cv;
	while(i<=n&&item[i].w<=cleft)
	{
		cleft-=item[i].w;
		value+=item[i].v;
		++i; 
	 } 
	if(i<=n) value+=item[i].v*cleft/item[i].w;
	return value; 
}

void backtrace(int i)
{
	if(i>n){//到达根节点且根节点处理完毕
		for(int j=1;j<=n;j++){
			best_x[j]=x[j];
		}
		best_v=cv;
		return;
	}
	else{
		if(cw+item[i].w<=c){//进入左子树 
			x[i]=1;//标记选取 ,物品装入 
			cw+=item[i].w;
			cv+=item[i].v;
			backtrace(i+1);
			cw-=item[i].w;
			cv-=item[i].v;
		}
		if(bound(i+1)>best_v){//进入限界右子树 
			x[i]=0;//不装 
			backtrace(i+1);
		}
	}
}

int main()
{
	cout<<"输入物品个数"<<endl; 
	cin>>n;
	cout<<"输入背包容量"<<endl;
	cin>>c; 
	cout<<"依次输入每个物品的价值和重量"<<endl; 
	for(int i=1;i<=n;i++){
		item[i].id=i;
		cin>>item[i].v;
		cin>>item[i].w;
		item[i].vw=item[i].v/item[i].w; 
	}
	sort(item+1,item+n+1,cmp);
//	print();
	backtrace(1);
	cout<<"可装入的最大价值:"<<best_v<<endl;
	cout<<"放入背包的物品编号:" ; 
	for(int i=1;i<=n;++i)
	if(best_x[i]==1) cout<<item[i].id<<" ";
	return 0;
}

分支限界法

​​​​​​​算法设计与分析第六章思维导图&&知识点总结 

分支限界法——装载问题

0-1背包问题-分支限界法(优先队列分支限界法)

#include<iostream>
#include<queue>
#include<vector> 
#include<algorithm>
using namespace std;
const int maxn=10050;

int n,W;
int best;
vector<int> bestX;

struct Awp{
	int v;
	int w;
}a[maxn];

struct node{
	int cv;       //当前价值 
	int cw;       //当前质量 
	int bound;  //限界
	vector<int> visited;
}; 

struct tmp{
	bool operator()(node x,node y)
	{
		return x.bound>y.bound;
	}
};
bool cmp(Awp a,Awp b){
	if((1.0*a.v/a.w)>(1.0*b.v/b.w))
	{
		return true;
	}
	else
	{
		return false;
	}
}
float getBound(node v){
	
	int i;
	int tempW=W;
	int  sum=0;
	for(i=0;i<v.visited.size();i++)
	{
		if(v.visited[i]==1){
			sum+=a[i].v;
			tempW-=a[i].w;
		}
		else continue;
			
	} 
	for(int j=i;j<n;j++){
		if(a[j].w>tempW){
			sum+=(a[j].v/a[j].w)*tempW;
			break;
		}
		else{
		 	sum+=a[j].v;
			tempW-=a[j].w;
		}
	} 
	
	return sum;
}
void knapsack()
{
	priority_queue<node,vector<node>,tmp> PQ; 
	struct node v;
	v.cv=0;
	v.cw=0; 
	v.bound=getBound(v);
//	cout<<v.bound<<endl; 
	PQ.push(v);
	while(!PQ.empty()){
		
		struct node vv=PQ.top();
		PQ.pop();
		
		int clevel=vv.visited.size(); 
		if(clevel==n){
			if(vv.cv>best){
				best=vv.cv;
				bestX=vv.visited;
			} 	
			continue;
		}
		
		struct node lc,rc;
		for(int i=0;i<clevel;i++)
		{
			lc.visited.push_back(vv.visited[i]);
			rc.visited.push_back(vv.visited[i]);
		}
		lc.visited.push_back(1);
		rc.visited.push_back(0);
			
		if(vv.cw+a[clevel].w<=W) 
		{
			lc.cw=vv.cw+a[clevel].w;
			lc.cv=vv.cv+a[clevel].v;
			lc.bound=getBound(lc);
		//	cout<<lc.bound<<endl;
			if(lc.bound>best) PQ.push(lc);
		} 
			
	
			rc.bound=getBound(rc);
			if(rc.bound>best){
				rc.cw=vv.cw;
				rc.cv=vv.cv;
				PQ.push(rc); 
			} 		
		//	cout<<rc.bound<<endl;	
	}
/*	for(int i=1;i<=n;i++)
		cout<<u.visited[i]<<' ';
	cout<<endl; */
}



int main()
{
//	cout<<"物品个数:";
	cin>>n;
	//cout<<"背包容量:" ;
	cin>>W;
// 	cout<<"物品的大小和价值";
	for(int i=0;i<n;i++){
		cin>>a[i].v;
		cin>>a[i].w;
	} 
	sort(a,a+n,cmp);
	
	for(int i=0;i<n;i++)
		cout<<"第"<<i+1<<"个物品价值 重量:\n"<<a[i].v<<' '<<a[i].w<<endl; 
	
	 knapsack();
	 cout<<best<<endl;
	for(int i=0;i<bestX.size();i++)
	{
		cout<<bestX[i]<<' ';
	}

	return 0;
 } 
 /*
 3 10
6 3
18 9
16 2

5 10
6 2
3 2
5 6
4 5
6 4
*/

最大团问题

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值