算法概述
算法的概念: 算法是指解决问题的一种方法或一个过程,更严格地讲,算法是由若干条指令组成的有穷序列。
程序的概念:程序是算法用某种程序设计语言的具体实现,程序可以不满足算法的有限性。
算法+数据结构=程序 ->算法是程序的灵魂。
程序设计:行为设计+结构设计。
行为设计:其结果是算法
结构设计:对要解决的问题定义数据结构 (包括物理结构和逻辑结构)
时间复杂度计算
主定理
递归树
递归与分治策略
#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;
}
#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;
}
#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;
}
最优子结构性质是指一个问题的最优解包含其子问题的最优解。在证明最优子结构性质时,通常需要使用归纳法或反证法。
归纳法证明最优子结构性质的步骤如下:
- 假设问题的最优解包含其子问题的最优解。
- 假设存在一个更优的解,该解不包含子问题的最优解。
- 通过比较两个解的值,证明假设的存在性是错误的。
- 根据归纳法的原理,可以得出结论:问题的最优解包含其子问题的最优解。
反证法证明最优子结构性质的步骤如下:
- 假设问题的最优解不包含其子问题的最优解。
- 通过比较两个解的值,证明假设的存在性是错误的。
- 根据反证法的原理,可以得出结论:问题的最优解包含其子问题的最优解。
通过以上的证明过程,可以得出结论:最优子结构性质成立。
贪心选择性质的证明是通过数学归纳法来完成的。首先,我们需要定义问题的最优解结构,并证明贪心选择性质成立。
-
定义问题的最优解结构:假设问题的最优解是S={a1, a2, …, ak},其中a1, a2, …, ak是问题的一个最优解的一部分。我们假设在S中存在一个非最优解S’={a1, a2, …, ak, ak+1},其中ak+1不是最优解的一部分。
-
证明贪心选择性质成立:我们需要证明,在S中存在一个贪心选择ak,使得S’={a1, a2, …, ak, ak+1}不是最优解。假设存在这样的贪心选择ak,那么我们可以将ak+1替换为ak,得到一个新的解S’'={a1, a2, …, ak},这个解比S更优。这与S是最优解的假设相矛盾。
-
通过数学归纳法证明贪心选择性质成立:我们可以通过数学归纳法来证明贪心选择性质成立。首先,我们证明问题的最优解结构中只包含一个元素的情况。然后,我们假设问题的最优解结构中包含k个元素,并证明在这个结构中存在一个贪心选择,使得结构中包含k+1个元素的解不是最优解。通过这样的归纳证明,我们可以得出贪心选择性质成立。
综上所述,贪心选择性质的证明是通过定义问题的最优解结构,并通过数学归纳法证明贪心选择性质成立。这样,我们可以通过贪心算法中的贪心选择来得到问题的最优解。
回溯算法
#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;
}
#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;
}
分支限界法
算法设计与分析第六章思维导图&&知识点总结
#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
*/