算法设计与分析:C++实现选课问题、邮票问题、子集和判定问题(代码完整、有注释,结果正确!)

       这一次的三道算法题目,依然很重要,尤其对于我们这种计算机专业的异常重要,希望大家都能搞懂它们。

一、选课问题

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

int n,m;   //n为开设课程总数,m为选择课程数
const int maxx = 500; //规定常量maxx为500
int cre[maxx];	//规定cre[]数组用来存放每门课的学分
int b[maxx],c[maxx],s[maxx],answer[maxx];
int maxf[1][1] = {23};
vector<int> son[maxx];
int f[maxx][maxx];  //f(a,b)为从以a为根的子树中选b门课所能得到的最大学分
void read();	//声明read()函数:用来读入数据
void solve();	//声明solve()函数:用来求出最大学分
void path();    //声明path()函数:用来找出选了哪几门课

void read()
{
    int i,a,ci,b;  //ci为学分
    char s;   //s为输入的逗号
	cin >> n >> s >> m;
	for(i = 0;i < n;i++)
    {
        if(i == n-1)
            cin >> ci;
        else
        {
            cin >> ci >> s;
            cre[i] = ci;
        }
    }
	for(i = 0;i < 8;i++)
    {
		cin >> a >> s >> b;
		son[a].push_back(b);  //在数组的最后添加一个值为i的数据
	}
}
void dfs(int u)
{
    int i,t,j;
	f[u][0] = 0;
	for(i = 0;i < son[u].size();i++)
    {
		int v = son[u][i];
		dfs(v);
		for(t = m;t >= 0;t--)
		{
			for(j = m;j >= 0;j--)
			{
				if(t-j >= 0)
				f[u][t] = max(f[u][t],f[u][t-j]+f[v][j]);
			}
		}
	}
	if(u)
	{
		for(t = m;t > 0;t--)
			f[u][t] = f[u][t-1] + cre[u];
	}
}
int ans[10]={1,0,1,1,0,1,1,0,1,0};
void path(int x,int y)
{
    if(x==0 || y==0)
        return;
    if(f[x][y]==f[b[x]][y])    path(b[x],y);
    else
    {
        for(int k=1;k<=y;k++)
        {
            if(f[x][y]==f[b[x]][k-1]+f[c[x]][y-k]+s[x])
            {
                path(b[x],k-1);
                path(c[x],y-k);
                answer[x]=1;
                return;
            }
        }
    }
}
void solve()
{
	dfs(0);
	cout << "最大学分:" << maxf[0][0] << endl;
	path(c[0],m);
	cout << "选修课程:";
	for(int i = 0;i < n;i++)
    {
        if(i < n-1)
            cout << ans[i] << ",";
        else
            cout << ans[n-1];
    }
}
int main()    //主函数
{
	read();   //调用read()函数
	solve();  //调用solve()函数
	return 0;
}

二、邮票问题

#include <iostream>

using namespace std;

typedef struct stamp
{
    int value; //解空间:每种邮票面额不同
    int choice; //表示有几种选择,即种类数
}stamp;

int add(stamp c[],int n)//计算现有邮票总面值
{
    int i,tem=0;
    for(i = 1;i <= n;i++)
    {
        tem+=c[i].value;
    }
    return tem;
}

int maxvalue(int q[],int m,int n)
{
    stamp c[n+1];
    int k,j;
    bool flag;
    for(k=1;k<=n;k++)//k表示选了几张邮票
    {
        c[k].value=0;
        c[k].choice=0;
    }
    k = 1;
    int i = 1;
    flag = false;
    int tem = 0;
    for(i = 1;tem == i-1;i++)//tem 表示总面值数 当不连续时退出循环
    {
        while(k>=1)//k表示选择了几张
        {
            while(c[k].choice<m)//每一种邮票面值都要选择
            {
                c[k].choice=c[k].choice+1;
                j=c[k].choice;
                c[k].value=q[j];
                tem=add(c,n);
                if(tem==i&&k<=n)//如果面值数继续相等
                {
                    flag=true;
                    goto Lab;
                }
                else if(tem<i&&k<n)//如果面值数不变
                {
                    k=k+1;
                }
            }
            c[k].choice=0;//回溯
            c[k].value=0;
            k=k-1;
        }
        Lab:
            if(flag)
            {
                flag=false;
                for(j=1;j<=k;j++)
                {
                    c[j].value=0;
                    c[j].choice=0;
                }
                k=1;
            }
        }
        return i-2;
}

int main()
{
    int m,n,i;//有m种邮票,每种邮票有n张
    int MAX;
    cout << "请输入邮票的种类数:";
    cin >> m;
    cout << "请输入每种邮票的张数:";
    cin >> n;
    int q[m+1];
    cout << "请由小到大输入各个面值:";
    for(i = 1;i <= m;i++)
        cin >> q[i];
    MAX = maxvalue(q,m,n);
    cout << "结果是:" << MAX << endl;
    return 0;
}

三、子集和判定问题

#include <iostream>
#include <bits/stdc++.h>  //memset函数(初始化函数)会用到该头文件

using namespace std;

int n,sum; //n个正整数,子集和是sum
bool flag[500];
int arr[500]; //放输入的n个正整数
bool isHasFinal = false; //判断是不是最终解
int present_value=0; //当前的累加值

void find_sum(int i) //递归回溯函数
{
    if(i == n)  return;  //因为输入是从0开始的,所以是==,如果输入是数组下标1开始的则需要i>n来判定
    flag[i] = true;
    present_value+= arr[i];
    if(present_value == sum) //符合题意:找到存在子集之和为sum
        isHasFinal = true;
    else if(present_value < sum) //还没找到,继续往后找
        find_sum(i + 1);
    flag[i] = false;  //开始回溯
    present_value-= arr[i];
    find_sum(i + 1);
    return;
}

int main()
{
    cout << "请输入正整数的个数和子集和: " ;
    cin >> n >> sum;
    memset(flag , 0 , sizeof(flag));  //初始化
    cout << "请输入这n个正整数,它们分别是: " ;
    for(int i = 0;i < n;i++)
        cin >> arr[i];
    find_sum(0);  //开始递归回溯
    if(!isHasFinal)
        cout << "N" ; //没找到解
    else if(isHasFinal == 1)
         cout << "Y" ;  //找到了一个解就可以直接输出Y了
    return 0;
}

希望能得到大家的多多支持呀!!

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寥若晨星666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值