算法设计与分析复习知识

算法设计与分析复习知识

归并排序

#include<iostream>
using namespace std;

void Marge(int a[],int b[],int s,int m,int e)
{
	int i = s,j = m,k = s;
	while (i < m && j < e)
	{
        if (a[i] <= a[j])
            b[k++] = a[i++];
        else
            b[k++] = a[j++];
    }
    while (i < m)
        b[k++] = a[i++];
    while (j < e)
        b[k++] = a[j++];
}

void Margesort(int a[],int b[],int start,int end)
{
	if(start < end)
	{
        // mid变量的作用域仅限于if语句块内,每次递归调用都会使用正确的mid值,若在外部定义则会出现在递归调用中保留的情况,可能出现错误
		int mid = start + (end - start)/2; 
		Margesort(a, b, start, mid);
        Margesort(a, b, mid + 1, end);
        Marge(a, b, start, mid, end);
        for (int i = start; i < end; ++i)
		{
            a[i] = b[i];
        }
	}
}

int main()
{
    int n;
	cin >> n;
	int r[n],b[n];
	for(int i=0;i<n;i++)
	{
		cin >> r[i];
	}
	Margesort(r,b,0,n);
	for(int i=0;i<n;i++)
	{
		cout << r[i] << " ";
	}
	return 0;
}

快速排序

int Partition(int a[], int low, int high) {
    int pivot = a[low];
    while(low < high)
    {
    	while(low < high && a[high] >= pivot)
    	{
    		high--;
		}
    	a[low] = a[high];
    	
    	while(low < high && a[low] <= pivot)
    	{
    		low++;
		}
    	a[high] = a[low];
    	
	}
	a[low] = pivot;
	return low;
}


void QuickSort(int r[], int low, int high) {
    if (low < high) {
        int pivot = Partition(r, low, high);
        QuickSort(r, low, pivot - 1);
        QuickSort(r, pivot + 1, high);
    }
    else
    	return;
}

int main() {
    int n;
    cin >> n;
    int r[n+1];
    for (int i = 1; i <= n; i++) {
        cin >> r[i];
    }
    r[0] = 0;
    QuickSort(r, 0, n - 1);
    for (int i = 1; i <= n; i++) {
        cout << r[i] << ' ';
    }
    cout << endl;
    
    return 0;
}

堆排序

#include<iostream>
using namespace std;

void HeapAD(int R[],int i,int n)
{
	R[0] = R[i];
	for(int j=2*i;j<=n;j=2*j)
	{
		if(j < n && R[j] < R[j+1]) // 判断n/2处的根节点左右孩子谁更大,谁大选谁
			j++;
		if(R[0] >= R[j])
			break;
		else
		{ // 交换孩子与根节点值
			R[i] = R[j];
			i = j;
		}
	}
	R[i] = R[0];
}

void HeapSort(int r[],int n)
{
    // 构造大根堆
	for(int i=n/2;i>0;i--)
	{
		HeapAD(r,i,n);
	}
	
    // 实现堆排序
	for(int i=n;i>1;i--)
	{
		int tmp = r[i];
		r[i] = r[1];
		r[1] = tmp;
		HeapAD(r,1,i-1);
	}
}

int main() {
    int n;
    cin >> n;
    int r[n+1];
    for (int i = 1; i <= n; i++) {
        cin >> r[i];
    }
    r[0] = 0;
    HeapSort(r,n);
    for (int i = 1; i <= n; i++) {
        cout << r[i] << ' ';
    }
    cout << endl;
    
    return 0;
}

活动安排问题

#include <iostream> 
using namespace std; 
 
template<class Type>
void GreedySelector(int n, Type s[], Type f[], bool A[]);
 
const int N = 11;
 
int main()
{
    //下标从1开始,存储活动开始时间
    int s[] = {0,1,3,0,5,3,5,6,8,8,2,12};
 
    //下标从1开始,存储活动结束时间
    int f[] = {0,4,5,6,7,8,9,10,11,12,13,14};
 
    bool A[N+1];
 
    cout<<"各活动的开始时间,结束时间分别为:"<<endl;
    for(int i=1;i<=N;i++)
    {
        cout<<"["<<i<<"]:"<<"("<<s[i]<<","<<f[i]<<")"<<endl;
    }
    GreedySelector(N,s,f,A);
    cout<<"最大相容活动子集为:"<<endl;
    for(int i=1;i<=N;i++)
    {
        if(A[i]){
            cout<<"["<<i<<"]:"<<"("<<s[i]<<","<<f[i]<<")"<<endl;
        }
    }
    return 0;
}
 
template<class Type>
void GreedySelector(int n, Type s[], Type f[], bool A[])
{
    A[1]=true;
    int j=1;//记录最近一次加入A中的活动
 
    for (int i=2;i<=n;i++)//依次检查活动i是否与当前已选择的活动相容
    {
        if (s[i]>=f[j])
        { 
            A[i]=true;
            j=i;
        }
        else
        {
            A[i]=false;
        }
    }
}

动态规划斐波那契

//此处采用动态规划的方法进行
//即从底自上运算,空间和时间消耗非常客观
void fib(int n)
{
	int f[n+1];
	f[1] = 1;
	f[2] = 1;
	for(int i = 3;i <= n;i++)
	{
		f[i] = f[i-1] + f[i-2];
	}
	cout << "fib数列为:" << f[n] << endl;
}

int main()
{
	int a;
	cout << "请输入一个整数:" << endl;
	cin >> a;
		fib(a);//调用fib函数进行运算
}

0/1背包问题

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

struct Goods{
	int w,v;
};

int main()
{
	int n,W;
	cin >> n >> W;
	int f[100][100];
	Goods goods[n];
	for(int i=0;i<n;i++)
	{
		cin >> goods[i].w >> goods[i].v;
	}
	for (int i = 0; i <= n; ++i)
	{
        for (int j = 0; j <= W; ++j)
		{
            f[i][j] = 0;
        }
    }
    
    // 对于动态递归,可使用下标为1的数组,便于管理三种状态(待装价值,当前价值,先前价值)。否则会出现数组越界现象
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=W;j++)
		{
			if(j < goods[i].w)
				f[i][j] = f[i-1][j];
			else
			{
				f[i][j] = max(f[i-1][j],f[i-1][j-goods[i].w] + goods[i].v);
			}
		}
	}
	cout << f[n][W] << endl;
	return 0;
}

网格最短路径问题

#include <iostream>
using namespace std;

int MinPath(int a[3][3],int m,int n){
	int dist[m][n],path[m][n];//dist存最短路径长度,path存决策.1向下走.0向右走
	dist[0][0] = a[0][0];
	path[0][0] = 0;
	int i,j;
	for(i=1;i<n;i++)
	{
		dist[0][i] = dist[0][i-1] + a[0][i];
		path[0][i] = 1;
	}
	for(j=1;j<m;j++)
	{
		dist[j][0] = dist[j-1][0] + a[j][0];
		path[j][0] = 0;
	}
	for(j=1;j<m;j++)
	{
		for(i=1;i<n;i++)
		{
			if(dist[j][i-1] < dist[j-1][i])
			{
				dist[j][i] = dist[j][i-1] + a[j][i];
				path[j][i] = 1;
			}
			else
			{
				dist[j][i] = dist[j-1][i] + a[j][i];
				path[j][i] = 0;
			}
		}
	}
	cout<<"回溯路径为:";
	for(i=m-1,j=n-1;i>0||j>0;){
		cout<<a[i][j]<<"<--";
		if(path[i][j] == 0)	i--;
		else j--;
	}
	cout<<a[0][0]<<endl;
	return dist[m-1][n-1];
}
int main(){
	int a[3][3] = {1,3,1,1,5,1,4,2,1};
	int dist = MinPath(a,3,3);
	cout<<"从左上角到右下角的最短路径为:"<<dist<<endl;
	return 0;
}

TSP旅行商问题

#include<iostream>
#include<cmath>
using namespace std;
#define N 9999
//TSP问题求解函数
void TSP(int n,int** graph,int location){
    //构建二维数组[i,2^n],j模拟集合个数
    int **D = new int*[n+1];  //建行0~n,为方便理解和表示,第0行未使用
    int **Rec = new int*[n+1];  //建立Rec
    for(int i=1;i<=n;i++){
    //建列表示集合
        D[i] = new int [(int)pow(2,n)]; 
        Rec[i] = new int [(int)pow(2,n)];
    }
    //初始化D、Rec
    for(int i=1;i<=n;i++){
        D[i][0]=graph[i][location]; //D[i,{}]
        Rec[i][0]= -1;
        for(int j=1;j<=(int)pow(2,n)-1;j++){
            D[i][j]=N;
            Rec[i][j] = -1;
        }
    }
    //动态规划
    for(int j=1;j<=(int)pow(2,n)-1;j++){    //对每一列求解
        for(int i=1;i<=n;i++){  //每一行找最短路径
            int min = N;
            if(((int)pow(2,i-1) & j) == 0){   //顶点集不能包含i
                int length = N;
                for(int k=1;k<=n;k++){
				    if((int)pow(2,k-1) & j ){ //若顶点在集合中
                        length = graph[i][k] + D[k][j-(int)pow(2,k-1)];
                        if(length < min){
                            min = length;
                            D[i][j] = min;
                            Rec[i][j] = k;//局部最优决策
                        }
                    }
                }
            }
        }
    }
    
    /*
	    (int)pow(2,n)-1 表示所有顶点都被访问过一次时的状态。
	    确保顶点 i 不在顶点集合,而(int)pow(2,location-1)表示只有起始顶点被访问的状态
		需要将顶点 j 中已经包含的顶点 i 剔除掉 
	*/ 
	cout<<"最短长度:"<<D[location][(int)pow(2,n)-1-(int)pow(2,location-1)]<<endl;//最短路径长度
	cout<<"最短路径为:"<<location;
    int row = location;
    int column = (int)pow(2,n)-1-(int)pow(2,row-1);
    while(column > 0){
        cout<< "->"<<Rec[row][column];
        row = Rec[row][column];
        column -= (int)pow(2,row-1);
    }
	cout<<"->"<<location<<endl;
}

int main(){
    cout<<"旅行家需要游历多少个城市?:"<<endl;
    int n;
    cin>>n;
    //建立二维数组模拟邻接矩阵
    int **graph=new int* [n+1];
    for(int i=1;i<=n;i++)
        graph[i] = new int[n+1];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cout<<"输入邻接矩阵graph["<<i<<"]["<<j<<"]的权:"<<endl;
            cin>>graph[i][j];
        }
    }
    cout<<"旅行家现在在第几个城市?"<<endl;
    int location;
    cin>>location;
    TSP(n,graph,location);   //TSP求解
    return 0;
} 

最长递增子序列问题

#include <iostream>
using namespace std;
int str[999];
int L[999];
int a[999][999];
int main()
{
	int n;
	cin >> n;
	int i,j,k;
	int count;
	int max;
	for(i=0;i<n;i++)
	{
		cin >> str[i];
	}
	for(i=0;i<n;i++)
	{
		L[i] = 1;
		a[i][0] = str[i];
	}
	for(i=1;i<n;i++)
	{
		max = 1;
		for(j=i-1;j>=0;j--)
		{
			if((str[i] > str[j]) && (max < L[j]+1))
			{ // 这个判断条件保证了最长子序列的递增性 
				max = L[j] + 1;
				L[i] = max;
				for(k=0;k<max-1;k++)
				{
					a[i][k] = a[j][k];
				}
			}
		}
		a[i][max - 1] = str[i];
	}
	for(count=0,i=1;i<n;i++)
	{
		if(L[count] < L[i])
			count = i;
	}
	cout<<"最长递增子序列是:";
 	for (i=0; i<L[count]; i++)
		cout<<a[count][i]<<" ";
 	return L[count];
}


int a[999][999]
int v[999],w[999]
int main()
{
	int n,v;
	int i,j;
	cin >> n >> v;
	for(i=1;i<=n;i++)
	{
		cin >> v[i] >> w[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=v;j++)
		{
			if(j<v[i])
			{
				a[i][j] = a[i-1][j];
			}
			else
			{
				a[i][j] = max(a[i-1][j],a[i-1][j-v[i]]+w[i])
			}
		}
	}
	cout << a[n][v];
	return 0;
}

最长子序列问题

#include <iostream>
#include <string>
#include <stack>
using namespace std;
void LCS(string s1,string s2)
{
    int m=s1.length()+1;
    int n=s2.length()+1;
    int **c;
    int **b;
    c=new int* [m];
    b=new int* [m];
    for(int i=0;i<m;i++)
    {
        c[i]=new int [n];
        b[i]=new int [n];
        for(int j=0;j<n;j++)
            b[i][j]=0;
    }
    for(int i=0;i<m;i++)
        c[i][0]=0;
    for(int i=0;i<n;i++)
        c[0][i]=0;
    for(int i=0;i<m-1;i++)
    {
        for(int j=0;j<n-1;j++)
        {
            if(s1[i]==s2[j])
            {
                c[i+1][j+1]=c[i][j]+1;
                b[i+1][j+1]=1;          //1表示箭头为  左上
            }
            else if(c[i][j+1]>=c[i+1][j])
            {
                c[i+1][j+1]=c[i][j+1];
                b[i+1][j+1]=2;          //2表示箭头向  上
            }
            else
            {
                c[i+1][j+1]=c[i+1][j];
                b[i+1][j+1]=3;          //3表示箭头向  左
            }
        }
    }
    for(int i=0;i<m;i++)                //输出c数组
    {
        for(int j=0;j<n;j++)
        {
            cout<<c[i][j]<<' ';
        }
        cout<<endl;
    }



    /*
		用于判断重复字段的元素
	*/ 
    stack<char> same;                   //存LCS字符
    stack<int> same1,same2;             //存LCS字符在字符串1和字符串2中对应的下标,方便显示出来
    for(int i = m-1,j = n-1;i >= 0 && j >= 0; )
    {
        if(b[i][j] == 1)
        {
            i--;
            j--;
            same.push(s1[i]);
            same1.push(i);
            same2.push(j);
        }
        else if(b[i][j] == 2)
                i--;
             else
                j--;
    }
    cout<<s1<<endl;                     //输出字符串1
    for(int i=0;i<m && !same1.empty();i++)      //输出字符串1的标记
    {
        if(i==same1.top())
        {
            cout<<1;
            same1.pop();
        }
        else
            cout<<' ';
    }
    cout<<endl<<s2<<endl;                //输出字符串2
    for(int i=0;i<n && !same2.empty();i++)      //输出字符串2的标记
    {
        if(i==same2.top())
        {
            cout<<1;
            same2.pop();
        }
        else
            cout<<' ';
    }
    cout<<endl<<"最长公共子序列为:";
    while(!same.empty())
    {
        cout<<same.top();
        same.pop();
    }
    cout<<endl<<"最长公共子序列长度为:"<<c[m-1][n-1]<<endl;
    for (int i = 0; i<m; i++)
    {
        delete [] c[i];
        delete [] b[i];
    }
    delete []c;
    delete []b;
}
int main()
{
    string s1="ABCPDSFJGODIHJOFDIUSHGD";
    string s2="OSDIHGKODGHBLKSJBHKAGHI";
    LCS(s1,s2);
    return 0;
}

最优二叉树搜索问题

#include <iostream>
#define MAXNUM 100
#define MAX 65536
using namespace std;
 
//p中为有序关键字k1到k5的搜索概率,k1<k2<k3<k4<k5
double p[MAXNUM] = {0.00, 0.15, 0.10, 0.05, 0.10, 0.20};
double q[MAXNUM] = {0.05, 0.10, 0.05, 0.05, 0.05, 0.10};
void optimal_bst(double e[][MAXNUM], int root[][MAXNUM], double w[][MAXNUM], int n)
{
    int i = 0, j = 0;
    //针对左或右孩子为空树情况初始化
    for(i = 1; i <= n + 1; i++)
    {
        e[i][i - 1] = q[i - 1];
        w[i][i - 1] = q[i - 1];
    }
    int l = 0;
    /*计算顺序如下:根据计算式:e[i,j] = e[i,r-1]+e[r+1,j
      首先计算节点个数为1的最优二叉树的代价e[1,1],e[2,2]……
      接着计算节点个数为1的最优二叉树的代价e[1,2],e[2,3]……
      ……
      最后计算结点个数为n的最优二叉树的代价e[1,n],利用之前保存的较少结点最优二叉树的结果.*/
    for(l = 1; l <= n; l++)
    {// 外层循环 l 表示当前考虑的节点范围的大小,从 1 到 n。
        for(i = 1; i <= n - l + 1; i++)
        {// 内层循环 i 和 j 表示当前考虑的子树的起始节点和结束节点。
            j = i + l - 1;
            e[i][j] = MAX;
            w[i][j] = w[i][j - 1] + p[j] + q[j];
            for(int r = i; r <= j; r++)
            {
                double t = 0;
                t = e[i][r - 1] + e[r + 1][j] + w[i][j];
                if(t < e[i][j])
                {
                    e[i][j] = t;
                    root[i][j] = t;
                }
            }
        }
    }
}
 
int main()
{
    double e[MAXNUM][MAXNUM];
    int root[MAXNUM][MAXNUM];
    double w[MAXNUM][MAXNUM];
 
    optimal_bst(e, root, w, 5);
 
    for(int i = 1; i <= 6; i++)
    {
        for(int j = 0; j <= 5; j++)
        {
            cout << e[i][j] << "  ";
        }
        cout << endl;
    }
}

近似串匹配问题

#include<iostream>
using namespace std;

int D[20][20]; // 填表矩阵设置为全局变量 

int min(int a,int b,int c)
{
	if(a<b && a<c) return a;
	else if(b<a && b<c) return b;
	else return c;
}

// 返回 P和 T的最小差别数 
int ASM(char P[],int m,char T[],int n)
{
	// 初始化第 0行 
	for(int j=1;j<=n;j++) D[0][j] = j;
	// 初始化第 0列
	for(int i=1;i<=m;i++) D[i][0] = i; 
	// 根据递推式依次计算每一列
	for(int j=1;j<=n;j++){
		for(int i=1;i<=m;i++){
			// 注意数组下标从 0开始,即P[i-1]对应模式P的第i个元素,T[j-1]为文本T的第j个元素 
			if(P[i-1]==T[j-1]) 
				D[i][j] = min(D[i-1][j-1],D[i-1][j]+1,D[i][j-1]+1); 
			else
				D[i][j] = min(D[i-1][j-1]+1,D[i-1][j]+1,D[i][j-1]+1);
		}
	} 
	return D[m][n]; 
}

int main()
{
	char P[5] = {'h','a','p','p','y'};
	char T[6] = {'h','s','p','p','a','y'};
	cout<<"最小差别数为:"<<ASM(P,5,T,6)<<endl;

	return 0;
}

藏宝图DFS问题

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

int edge[999][999];
int visited[999];

int DFS(int u, int v, int n) {
    visited[u] = 1;
    if (u == v) {
        return 1;
    }
    for (int i = 0; i < n; i++) {
        if (edge[u][i] == 1 && visited[i] == 0) {
            if (DFS(i, v, n) == 1) {
                return 1;
            }
        }
    }
    return 0;
}

int main() {
    int n, start, end;
    cout << "请输入山洞数量:";
    cin >> n;

    for (int i = 0; i < n; i++) {
        visited[i] = 0;
        for (int j = 0; j < n; j++) {
            edge[i][j] = 0;
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
        	if(i == j)
        		edge[i][j] = 1;
        	else
        	{
        		cout << "请输入" << i << "山洞与" << j << "山洞之间的连通关系(0表示不连通,1表示连通):" << endl;
            	cin >> edge[i][j];
			}
        }
    }

    cout << "请输入寻宝图所在山洞编号:";
    cin >> end;
    cout << "请输入猎人起始的山洞编号:";
    cin >> start;

    // 调用 DFS 函数判断猎人是否能找到寻宝图
    if (DFS(start, end, n) == 1) {
        cout << "猎人能够找到寻宝图!" << endl;
    } else {
        cout << "猎人无法找到寻宝图!" << endl;
    }
    return 0;
}

图着色问题

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

const int maxn = 1005;
int G[maxn][maxn], color[maxn];//用于存储图中的边--用于存储每个节点的颜色 
int n, m; //n表示图中节点的数量,m表示可供选择的颜色数目。
 
bool ok(int u, int c) {
    for (int i = 1; i <= n; i++) {
        if (G[u][i] == 1 && color[i] == c) // 判断是否相邻节点已经着色 c 
            return false;
    }
    return true;
}
 
bool dfs(int u) {
    if (u > n)
        return true;
    for (int i = 1; i <= m; i++) {
        if (ok(u, i)) {
            color[u] = i;
            if (dfs(u + 1))
                return true;
            color[u] = 0;
        }
    }
    return false;
}
 
int main() {
    memset(G, 0, sizeof(G));//初始化邻接矩阵为0
    memset(color, 0, sizeof(color));//初始化颜色为0
    int e;//e表示图中边的数量
    cin >> n >> e >> m;
    for (int i = 0; i < e; i++) {
        int u, v;
        cin >> u >> v;
        G[u][v] = G[v][u] = 1;
    }
 
    if (dfs(1)) { // 从第1个顶点开始进行递归着色
        cout << "Yes" << endl;
        for (int i = 1; i <= n; i++) {
            cout << "结点 " << i << " 的颜色为: " << color[i] << endl;
        }
    }
    else {
        cout << "No" << endl;
    }
    return 0;
}

N皇后问题

#include <iostream>
#include <cmath>
using namespace std;
int N,res=0;

int queen(int arr[],int r)
{
	if(r == N)
		res++;
	else
	{
		for(int c=0;c<N;c++)
		{
			arr[r] = c;
			bool can = true;//用于标记是否可以放皇后
			for(int x=0;x<r;x++)
			{								 	 //不在同一行
				if(arr[r] == arr[x] ||			 //同一列的情况
				abs(r-x) == abs(arr[r] - arr[x]))//同一对角线的情况(斜率判断) 
					can = false;
				break;
			}
		}
	}
	return res;
}

int main(){
    cin >> N;
    int arr[N];
    cout<<queen(arr,0);
    return 0;
}

批处理作业调度问题

#include <iostream>
using namespace std;

int n;   			//作业数
int M[100][100];    //M[i][j]表示第i个作业在机器j上需要处理的时间
int x[100];   		//x[i]表示第i个处理的作业为x[i]
int bestx[100];   	//x[i]的最优值
int f1;   			//作业在机器1上完成处理的时间
int f2[100];   		//f2[i]表示第i个作业在机器2上完成处理的时间
int f;   			//用于记录前i个作业在机器2上完成处理的时间和
int bestf;   		//f的最优值

void Swap(int &a,int &b)   //交换函数
{
    int temp;
    temp=a;
    a=b;
    b=temp;
}

void Backtrack(int i)
{
    if(i>n)   //每到达一个叶子结点,一定是产生了一个最优解,因此要更新之前最优解的值
    {
        if(f<bestf)   //更新最优解
        {
            for(int j=1;j<=n;j++)
                bestx[j]=x[j];
            bestf=f;
        }
    }

    else
    {
        for(int j=i;j<=n;j++)   //控制展开 i-1 层结点的各个分支。例如当i=1时,表示在整棵排列树的根结点处,刚要开始探索结点,这时可以展开的分支有1、2、3……
        {
            f1+=M[x[j]][1];   //计算第 i 个作业在机器1上的完成处理的时间
            if(f2[i-1]>f1)   //如果第 i-1 个作业在机器2上的完成处理的时间大于第i个作业在机器1上的完成处理的时间,那么第i个作业想进入机器2,就要等第 i-1 个作业在机器2上完成后再说
                f2[i]=f2[i-1]+M[x[j]][2];
            else   //否则,第i个作业可以在机器1上完成处理后直接进入机器2。
                f2[i]=f1+M[x[j]][2];
            f+=f2[i];   //计算完第i个作业在机器2上的完成处理的时间,就可以计算出前i个作业在机器2上完成处理的时间和了
            if(f<bestf)   //截止到这,已经得到一个前i个作业在机器2上完成处理的时间和f,如果f比之前记录的前i个作业在机器2上的完成处理的时间和的最优值bestf都要小,就可以生成第i层结点的孩子结点,继续探索下一层
            {
                Swap(x[i],x[j]);   //把处于同一层的并且使f更小的那个结点拿过来,放到正在探索的这个结点处(这里结合排列数的图可以更好地理解)
                Backtrack(i+1);   //继续探索以第i层结点为根结点的子树
                Swap(x[i],x[j]);   //探索完要回溯时,只要做探索前的反“动作”就可以了
            }
           f-=f2[i];   //探索完要回溯时,只要做探索前的反“动作”就可以了
           f1-=M[x[j]][1];   //探索完要回溯时,只要做探索前的反“动作”就可以了
        }
    }
}

void inPut()   //输入函数
{
    cout<<"请输入作业的个数n:"<<endl;
    cin>>n;
    cout<<"请分别输入n个作业在机器1和机器2上各自需要处理的时间(分两行):"<<endl;
    for(int i=1;i<=2;i++)
    {
        for(int j=1;j<=n;j++)
            cin>>M[j][i];
    }
}

void initialize()   //初始化函数
{
    for(int i=1;i<=n;i++)
        x[i]=i;   //初始化当前作业调度的一种排列顺序
    bestf=10000;   //此问题是得到最佳作业调度方案以便使其完成处理时间和达到最小,所以当前最优值bestf应该初始化赋值为较大的一个值
}
void outPut()   //输出函数
{
    cout<<"这"<<n<<"个作业的最佳调度顺序为:"<<endl;
    for(int i=1;i<=n;i++)
        cout<<bestx[i]<<" ";
    cout<<endl;
    cout<<"该作业调度的完成时间和为:"<<endl;
    cout<<bestf<<endl;
}

int main()
{
    inPut();
    initialize();
    Backtrack(1);
    outPut();
    return 0;
}

实际案例

建筑公司铺路

某城市规划公司计划建造一条由东向西的主道路,该主道路要穿过一个有n个住宅楼的社区,从每个住宅楼都要有条辅道路沿最短路经(或南或北)与主道路相连。如果给定n个住宅楼的位置,即它们的x坐标(东西向)和y坐标(南北向),应该如何确定主道路的最优位置?即:使各住宅楼到主道路之间的辅道路长度总和最小的位置? 要求:给定n个住宅楼的位置,求解各住宅楼到主道路之间的辅道路最小长度总和。
输入(Input):
(1)第1行是住宅楼数n,1≤n≤10000:
(2)接下来n行是住宅楼的位置,每行2个整数x和y(空格相隔),-10000≤x,y≤10000。
输出(Output)
各住宅楼到主道路之间的辅道路最小长度总和,
示例(Sample):
输入:
5
1 2
2 2
1 3
3 -2
3 3
输出:
6

代码实现

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

typedef struct Build{
  int x,y; // 给定x坐标和y坐标  
};

/*
	sort 函数的使用:(start,end,cmp),而cmp是一个bool值,若编写cmp为返回“a < b”,则为降序排列;否则为升序排列
*/

bool cmp(Build a,Build b)
{
	return a.x < b.x;
}

int main()
{
	int n; // 建筑的数量
    cin >> n;
    
    Build building[n]; // 创建住宅结构体
    for(int i=0;i<n;i++){
		cin >> building[i].x >> building[i].y;
    }
    
    sort(building,building+n,cmp); // 按x坐标进行排序,便于创建主干道
    
    int mainroad = building[n/2].x; // 以中间位置的建筑为中心,创建主干道
    
    int roadlength = 0;
    for(int i=0;i<n;i++){
		if(building[i].x == mainroad) // 主干道上的建筑不计入铺路长度
            continue;
        roadlength += abs(building[i].y - building[n/2].y);
    }
    
    cout << roadlength << endl;
    return 0;
}

过山车问题(0/1背包问题的变体)

设在某游乐场有n个游客 {1,2,… n}要乘坐承载重量为W过山车。第i个人的重量是wi,1≤in,确定这n个人乘坐过山车的一个方案,使得过山车能够乘坐尽可能多的人。 要求:对于给定的n个人的重量,计算过山车上乘坐最多的人数。
输入(Input)。
(1)2个正整数,分别表示人数n和过山车承载重量W;
(2)n个正整数,表示人的重量(空格相隔)0 输出(Output) 最多乘坐过山车的人数。
示例(Sample):
输入(Input)
6 50
2 3 13 8 80 20
输出(Output):
5

###代码实现

贪心法求解

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

bool cmp(int a, int b)
{
    return a > b;
}

int main()
{
    int n, W;
    cin >> n >> W;
    int count = 0;
    int weights[n];
    for (int i = 0; i < n; i++)
    {
        cin >> weights[i];
    }

    sort(weights, weights + n, cmp);

    for (int i = 0; i < n && W != 0; i++)
    {
        if (weights[i] < W)
        {
            count++;
            W -= weights[i];
        }
    }
    cout << count << endl;
    return 0;
}

动态规划法求解

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

int main() {
    int n, W;
    cin >> n >> W;
    int w[n];
    for (int i = 0; i < n; ++i) {
        cin >> w[i];
    }

    int f[n + 1][W + 1];
    for (int i = 0; i <= n; ++i) {
        for (int j = 0; j <= W; ++j) {
            f[i][j] = 0;
        }
    }

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= W; ++j) {
            // 不选择第i个人
            f[i][j] = f[i - 1][j];
            // 选择第i个人
            if (j >= w[i - 1]) {
                f[i][j] = max(f[i][j], f[i - 1][j - w[i - 1]] + 1);
            }
        }
    }

    cout << f[n][W] << endl;

    return 0;
}

北京奥森机器人(游艇租借问题变体)

北京奥林匹克森林公园北园有一批“任逍遥”伴游机器人,公园内设置了n个伴游机器人出租站1,2,…,n。游客可以在这些出租站租用伴游机器人,并在任何一个出租站归还。伴游机器人出租站i到伴游机器人出租站j之间的租金为r(i,j)(其中1≤i<j≤n)
要求:计算出从伴游机器人出租站1到伴游机器人出租站n所需要的最少租金。
输入(Input)
(1)伴游机器人出租站n;
(2)接下来n-1行的r(i,j)(其中1≤i<j≤n)
输出(Output)
从伴游机器人出租站1到伴游机器人出租站n所要的最少租 金
示例(Sample)
输入(Input)
3(站数)
5 15(第一站到其他相应各站的租金)
7(第二站到其他相应各站的租金)
输出(Output)
12

代码实现

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

int main()
{
	int n; // 站数 
	cin >> n;
	int i,j,k;
	
	// 初始化站台租金 
	int r[100][100];
	for (int i = 0; i < n; i++)
	{
        for (int j = 0; j < n; j++)
		{
			if(i == j)
				r[i][j] = 0;
			else
				r[i][j] = 999;
        }
    }
	
	for(i=0;i<n;i++)
	{
		for(j=i+1;j<n;j++)
		{
			cin >> r[i][j];
		}
	}
	
	for(i=0;i<n;i++)
	{
		for(j=i+1;j<n;j++)
		{
			for(k=i+1;k<j;k++)
			{
				if (r[i][k] != 999 && r[k][j] != 999)
				{// 判断是否存在可走的路
                    r[i][j] = min(r[i][j], r[i][k] + r[k][j]); // 状态转移方程,实现求最小租金
                }
			}
		}
	}
	
	cout << r[0][n-1];
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值