几个经典算法


蛮力算法

子集

#include<iostream>
using namespace std;
#define MAX 1000
int main() {
    int n;
    int a[MAX];
    int tol;//子集的个数
    n=4;
    for(int i=0; i<n; i++) {
        cin>>a[i];
    }
    tol=(1<<n)-1; //子集的个数
    for(int i=0; i<=tol; i++) {
        for(int j=0; j<n; j++)
            if(i&(i<<j)) cout<<a[j];  //i<<j相当于对每一个进行标记 
        cout<<" "<<endl;
    }

}

递归算法

1.输出全排列

#include<iostream>
using namespace std;
void Perm(int list[],int k,int m) {
    if(k==m) {
        for(int i=0; i<=m; i++)
            cout<<list[i]<<" ";
        cout<<endl;
    } else {
        for(int j=k; j<=m; j++) {
            swap(list[k],list[j]);
            Perm(list,k+1,m);
            swap(list[k],list[j]);
        }
    }

}
int main() {
    int list[]= {1,2,3,4,5};
    Perm(list,0,3);
}

2.正整数n的划分算法

#include <iostream>
using namespace std;

int split(int n,int m)
{
    if(n==1||m==1) return 1;
    else if (n<m) return split(n,n);
    else if(n==m) return split(n,n-1)+1;
    else return split(n,m-1)+split(n-m,m);
}

int main()
{
    int n;
    while (cin>>n)
        cout<<split(n, n)<<endl;
    return 0;
}

    //对一个段进行递归调用
    return select(j+1, right, k-j+left-1);
    else return select(left, j-1, k);
}

int main()
{
    int n, k;
    while (cin>>n>>k)
    {
        for (int i=0; i<n; i++)
            cin>>a[i];
        cout<<select(0, n-1, k)<<endl;
    }
    return 0;
}

3.半数集问题的递归算法

#include<iostream>            
using namespace std;

int a[1001];
int comp(int n)
{
    int ans=1;
    if(a[n]>0)return a[n];
    for(int i=1;i<=n/2;i++) 
        ans+=comp(i);
    a[n]=ans;
    return ans;
}

int main()
{
    int n;
    while(cin>>n)
    {
        memset(a,0,sizeof(a));
        a[1]=1;
        cout<<comp(n)<<endl;
    }
    return 0;
}

分治算法

选择问题
//采用分治策略找出第k小元素的算法

#include <iostream>
using namespace std;

#define NUM 1001
int a[NUM];
int select(int left, int right, int k)
{   
    //找到第k小的元素
    if (left >= right) return a[left];
    int i = left;
    int j = right+1; 
    //把最左边的元素作为分界数据
    int pivot = a[left];
    while (true) 
    {
        do {
            i = i+1;
        } while (a[i] < pivot);
        do {
            j = j-1;
        } while (a[j] > pivot);
        if (i >= j) break;
        swap(a[i], a[j]);
    }
    if (j-left+1 == k) return pivot;
    a[left] = a[j];
    a[j] = pivot;
    if (j-left+1 < k)
        return select(j+1,right,k-j+left-1);
        else return select(left,j-1,k);
}
    选择第K个大的数
#include<iostream>
using namespace std;
void swap(int *a, int *b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

int partition(int arr[], int left, int right, int pivotIndex)
{
    int storeIndex = left;
    int pivotValue = arr[pivotIndex];
    int i;

    swap(&arr[pivotIndex],&arr[right]);

    for (i = left; i < right; i ++)
    {
        if (arr[i] > pivotValue)
        {
            swap(&arr[i],&arr[storeIndex]);
            storeIndex++;
        }
    }
    swap(&arr[storeIndex],&arr[right]);
    return storeIndex;
}

int findKMax(int arr[], int left, int right, int k)
{
    int nRet;
    int pivotIndex = left + 1;

    nRet = partition(arr,left,right,pivotIndex);
    if (nRet < k)
    {
        return findKMax(arr,nRet+1,right,k);
    }
    else if (nRet > k)
    {
        return findKMax(arr,left,nRet-1,k);
    }

    return nRet;
}


int main()
{
    int i,k,nRet;
    int arr[] = {8,3,4,1,9,7,6,10};

    scanf("%d",&k);
    nRet = findKMax(arr,0,7,k-1);

    printf("The Kth Max Number locate in %d is :%d\n",nRet,arr[nRet]);
    for (i = 0; i < 8; i++)
    {
        printf("%3d",arr[i]);
    }
    return 0;
} 

/循环赛程表

#include <stdio.h>
#define MAX 100

int a[MAX][MAX];

void Copy(int tox, int toy, int fromx, int fromy, int r)
{
    for (int i=0; i<r; i++)
        for (int j=0; j<r; j++)  
            a[tox+i][toy+j] = a[fromx+i][fromy+j];
}
//构造循环赛日程表,选手的数量n=2^k
void Table(int k)
{   
    int i, r;
    int n = 1 << k; 
    //构造正方形表格的第一行数据
    for (i=0; i<n; i++)
        a[0][i] = i + 1;
        //采用分治算法构造整个循环日程赛表
    for (r=1; r<n; r<<=1)
        for (i=0; i<n; i+=2*r)
        { 
            Copy(r, i + r, 0, i, r);
            Copy(r, i, 0, i + r, r);
        }
}

void Out(int n)
{ 
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++) 
            printf("%3d", a[i][j]);
        printf("\n");
    }
    printf("\n");
}

int main()
{ 
    int k;
    while (scanf("%d", &k) && k)
    { 
        int n = 1 << k; 
        Table(k); 
        Out(n);
    }
    return 0;
}

动态规划

1.矩阵链乘积

#include<iostream>
using namespace std;
int m[100][100];
int p[100],s[100][100];
int k;
int  TraceBack(int i,int j) {
        if(m[i][j]>0) return m[i][j];
        if(i==j) return 0;
        int u=TraceBack(i,i)+TraceBack(i+1,j)+p[i-1]*p[k]*p[j];
        s[i][j]=i;
        for(int k=i+1; k<j; k++) {
                int t=TraceBack(i,k)+TraceBack(k+1,j)+p[i-1]*p[k]*p[j];
                if(t<u) {
                        u=t;
                        s[i][j]=k;
                }
                m[i][j]=u;
                return u;
        }
}

2.最多单减子序列

#include<iostream>
using namespace std;
#define MAX 1000
int a[MAX] = {2,1,3};
int select(int left,int right,int k) {
    if(left>=right) return a[left];
    int i =left;
    int j = right+1;
    int pivot = a[left]; //把第一个设为界点
    while(true) {
        do {
            i++;
        } while(a[i]<pivot);
        do {
            j--;
        } while(a[j]>pivot);
        if(i>=j) break;
        swap(a[i],a[j]);
    }
    if(j-left+1==k) return pivot; //该界点就是要找的数
    a[left]=a[j];
    a[j]=pivot;
    if(j-left+1<k) return select(j+1, right, k-j+left-1);
    else return select(left,j-1,k);
}
int main() {
//  int a[3] = {2,1,3};
    cout<<select(0,2,2);
}

3.计算0-1背包的动态规划算法

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

#define NUM 50
#define CAP 1500
int v[NUM];
int w[NUM];
int p[NUM][CAP];
//形参c是背包的容量w,n是物品的数量
void knapsack(int c, int n) 
{ 
    int jMax=min(w[n]-1,c); 
    for( int j=0; j<=jMax; j++) 
        p[n][j]=0; 
    for( int j=w[n]; j<=c; j++) 
        p[n][j]=v[n];
    for( int i=n-1; i>1; i--) 
    { 
        jMax=min(w[i]-1,c); 
        for( int j=0; j<=jMax; j++) 
            p[i][j]=p[i+1][j]; 
        for(int j=w[i]; j<=c; j++) 
            p[i][j]=max(p[i+1][j], p[i+1][j-w[i]]+v[i]); 
    } 
    p[1][c]=p[2][c]; 
    if (c>=w[1]) 
        p[1][c]=max(p[1][c], p[2][c-w[1]]+v[1]); 
} 

void traceback( int c, int n, int x[ ]) 
{ 
    for(int i=1; i<n; i++) 
    {
        if (p[i][c]==p[i+1][c]) x[i]=0; 
        else { x[i]=1; c-=w[i]; } 
    }
    x[n]=(p[n][c])? 1:0; 
} 

int main () 
{
    int x[NUM];
    int W;
    int n;
    while (scanf("%d", &W) && W) 
    {
        scanf("%d", &n);
        for (int i=1; i<=n; i++)
            scanf("%d%d", &w[i], &v[i]);
        memset (p, 0, sizeof(p));
        knapsack(W, n);
        printf("%d\n", p[1][W]);
        traceback(W, n, x);
        for (int i=1; i<=n; i++)
            if (x[i]) printf("%d ", i);
        printf("\n");
    }
    return 0;
}

4.计算最大字段和的动态规划算法的最优解

#include <stdio.h>

#define NUM 1001
int a[NUM];
int MaxSum(int n, int &besti, int &bestj)
{
    int sum=0; 
    int b=0;
    int begin = 0;
    for (int i=1;i<=n;i++)
    {
        if (b>0) b+=a[i]; 
        else {b=a[i];begin = i;}
        if (b>sum) 
        {
            sum = b; 
            besti = begin; 
            bestj = i;
        }
    }
    return sum;
}

int main() 
{
    int n;
    int besti, bestj;
    while (scanf("%d", &n) && n) 
    {
        besti = 0;
        bestj = 0;
        for (int i=1; i<=n; i++)
            scanf("%d", &a[i]);
        printf("%d\n", MaxSum(n, besti, bestj));
        printf("From %d to %d\n", besti, bestj);
    }
    return 0;
}

贪心算法

//删数问题 ,找最近下降点

#include<iostream>
#include<String>
using namespace std;
int main() {
    string a;
    int k;
    cin>>a>>k;
    if(k>=a.size()) a.erase();
    else while(k>0) {
        int i;
        for(i=0; (i<a.size()-1)&&a[i]<=a[i+1]; i++);
        a.erase(i,1);
        k--;
        }
    while(a.size()>1 && a[0]=='0')
        a.erase(0,1);
    cout<<a<<endl;
}

删数问题

#include<iostream>
#include<string>
using namespace std;
int main()
{
   string n;
   int s,i,x,l,m;
   while(cin>>n>>s)
   {
        i=-1,m=0,x=0;
        l=n.length(); 
        while(x<s&&m==0)
         {
             i++;
             if(n[i]>n[i+1])//出现递减,删除递减的首数字 
              {
                  n=n.erase(i,1);
                  x++;// x统计删除数字的个数 
                  i=-1;//从头开始查递减区间 
              } 
             if(i==l-x-2&&x<s)
             m=1;//已经无递减区间,m=1脱离循环 
         } 
     cout<<n.substr(0,l-s+x)<<endl;//只打印剩下的左边l-(s-x)个数字 
   } 
   return 0;   
}

回溯算法

轮船装载(回溯)

#include<iostream>
using namespace std;
#define NUM 100             //解空间树 
int n;     //集装箱数量
int c;     //轮船装在数量
int w[NUM];//集装箱重量数组
int x[NUM];//解向量
int r;     //剩余集装箱重量
int cw;    //当前轮船载重量
int bestw; //当前最优载重量
int bestx[NUM];//当前最优解
void Backtrack(int t) {
    //到达叶子节点
    if(t>n) {
        if(cw>bestw) {    //更新最优解
            for(int i=1; i<=n; i++)
                bestx[i] = x[i];
            bestw = cw;
        }
        return;
    }
    //更新剩余集装箱的重量
    r-= w[t];
    //搜索左子树
    if(cw+w[t]<=c) {
        x[t]=1;
        \
        cw+=w[t];
        Backtrack(t+1);
        cw-=w[t];//恢复 状态
    }

    //搜索右子树
    if(cw+r>bestw) {
        x[t]=0;
        Backtrack(t+1);
    }

    r+= w[t];//恢复状态
}

N皇后问题

#include<iostream>
#include<cmath>
using namespace std;
#define NUM 20
int n=8;
int x[NUM]; //记录解向量,列号
int sum=0; //解的个数

inline bool Place(int t) {
    int i;
    for(i=1; i<t; i++) {
        if((abs(t-i) == abs(x[i]-x[t])) || (x[i]==x[t]))
            return false;
    }
    return true;  //只要不满足循环就返回true
}
void Backtrack(int t) {
    int i;//叶子节点
    if(t>n) {
        sum++;
        for(i=1; i<=n; i++) {
            cout<<x[i];
        }
        cout<<endl;
    } else {
        for(i=1; i<=n; i++) {
            x[t]=i;
            if(Place(t)) Backtrack(t+1);
        }
    }
}
int main() {
    //cin>>n;
    Backtrack(1);
    cout<<"Total="<<sum<<endl;
}

分支限界算法

装载问题分支限界算法的实现

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

#define NUM 100
int n;//集装箱的数量
int c;//轮船的载重量
int w[NUM];////集装箱的重量数组

int MaxLoading()
{
    queue<int> Q;
    Q.push(-1);
    int i = 0;
    int Ew = 0;
    int bestw = 0;
    int r = 0;
    for(int j=1; j<n; j++)
        r += w[j];
    while (true)
    {
        int wt = Ew+w[i];
        if (wt<=c)
        {
            if (wt>bestw) bestw = wt;
            if (i<n-1) Q.push(wt);
        }
        if (Ew+r>bestw && i<n-1) Q.push(Ew);
        Ew = Q.front();
        Q.pop();
        if (Ew==-1)
        {
            if (Q.empty()) return bestw;
            Q.push(-1);
            Ew = Q.front();
            Q.pop();
            i++;
            r -= w[i];
        }
    }
    return bestw;
}

int main()
{
    while(scanf("%d%d", &c, &n)!=EOF)
    {
        for(int i=0; i<n; i++)
            scanf("%d",&w[i]);
        int ans  =  MaxLoading();
        if (ans) printf("%d\n", ans);
        else printf("No answer!\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lewyu521/article/details/78559920