这一次的三道算法题目,依然很重要,尤其对于我们这种计算机专业的异常重要,希望大家都能搞懂它们。
一、选课问题
#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;
}
希望能得到大家的多多支持呀!!