题目内容:某船最高载重量为300吨,现有重量为101,78,92,45,301,117,85,210的八块金子,在不超过最高载重的情况下,从中选择任意块金子使船运金重量达到最高。
做法一:二进制转化法
做法分析:现有8块金子,每块金子有两种情况:选用或者不选用,选用可以用1代表,不选用可以用0代表。这样的话从八块金字选用情况有:00000001到11111111共254种情况。最接近船载重的情况便是最优解。
#include <stdio.h>
#include <stdlib.h>
int boat_max = 300;//船的最高载重量为300吨
int weight[10] = {101,78,92,45,301,117,85,210};//存放每块金子重量的数组
int b[10];//各金子有无情况的数组
/*bin函数,用于将十进制数字转化成二进制,存入数组中*/
/*此段代码随着n的值从1到255,转化成二进制就是从00000001到11111111*/
void bin(int n)
{
int i = 0;
while(n > 0) //把十进制n转化成二进制
{
b[i] = n % 2;
i++;
n = n / 2;
}
for(;i < 8; i++) //当十进制数不够八位时,将剩下的高位补0
{
b[i] = 0;
}
}
int main()
{
int i, n, flag, temp, max;
n = 0;
temp = 1; //记录中间变量
for(i = 0; i < 8; i++)
{
n += temp;
temp *= 2;
}
max = 0; //最大值
flag = 0; //标记函数
for(i = 1; i <= n; i++)
{
bin(i); //把i转化成二进制存到数组里
temp = weight[0]*b[0]+weight[1]*b[1]+weight[2]*b[2]+weight[3]*b[3]+weight[4]*b[4]+weight[5]*b[5]+weight[6]*b[6]+weight[7]*b[7];
//temp的值就是在此情况下,选用金子的重量
if(temp > max && temp <= boat_max) //temp比当前存下的值大,且不超船的最大载重
{
max = temp; //满足if中的条件,表示情况为当前最优值
flag = i; //存下每个金子的选用情况的十进制数
}
}
//循环结束后max就是此题目的最优解,每块金子的选用情况可以由flag转化成二进制后得到。
printf("此船此次运金的最大重量为:%d吨\n", max);
printf("选用金子为:\n");
bin(flag);
for(i = 0; i < 8; i++)
{
if(b[i] == 1)
{
printf("序号:%d,重量:%d吨\n", i+1, weight[i]);
}
}
return 0;
}
做法二:动态规划法
分析:利用数组和动态规划,来找到最优解。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *fp, *fp1;
char fp_line[1024];
char name[50][30];
char name_temp[30];
int relation[40][40];
int hang = -1;
int cmp(char *a, char *b)
{
int i;
for(i = 0; a[i] != '\0'; i++)
{
if(a[i]!= b[i])
{
return -1;
}
}
return 1;
}
int main()
{
int i, j, c1, max;
int name_number = 0;
int flag;
fp = fopen("relation.txt","rb");
while (!feof(fp))
{
fgets(fp_line, 1024, fp); //每次读文件的一行
flag = 0;
j = 0;
for(i = 0; fp_line[i] != '\0'; i++)
{
c1 = fp_line[i]; //当前字符
if(flag && c1 == '\t') //flag为真说明已存入汉字,当前字符为制表符说明名字已读完
{
break;
}
if((c1 >= '0' && c1 <= '9')||c1 == ' ' || c1 == '.' || c1 == '\n' || c1 == '\t')
{
continue;
}
else //上面的判断条件都不满足,剩下的就是汉字
{
flag = 1;
name[name_number][j++] = fp_line[i]; //把这个汉字的一半先存入字符串,再读下一字符
}
}
name_number++; //字符串数组的下标加一,再存下一行的名字
}
printf("各学生序号如下:\n");
for(i = 0; i < name_number; i++)
{
printf("(%d:%s)\t",i+1, name[i]);
if(i% 5 == 4 && i != 0)
printf("\n");
}
fclose(fp);
fp1 = fopen("relation.txt","rb");
while (!feof(fp1))
{
fgets(fp_line, 1024, fp1);
flag = 0;
j = 0;
hang++;
for(i = 0; fp_line[i] != '\0'; i++)
{
c1 = fp_line[i];
if(c1 == '\t') //识别到制表符,说明现在到了第二个名字开始的位置
{
flag = 1; //代表着取名字的操作可以开始了
continue;
}
if(c1 == ' ' || c1 == ',' || fp_line[i+1] == '\0') //这些都是名字结束后紧接着的字符,从这里把之前存下来的名字取出
{
for(j = 0; j < name_number; j++) //从本班第一个到最后一个遍历,看刚取出的name_temp序号是多少
{
if(cmp(name[j], name_temp)== 1) //cmp是自己写的一个小函数
{ //从字符串第一个字符判断到最后一个字符,作用是判断两个字符串是否相等
relation[hang][j] = 1; //把矩阵的这个位置赋值成1,表示这个人选择name_temp存下的人当朋友。
break;
}
}
for(j = 0; j < 20; j++) //把name_temp赋成空,存下一个名字用
{
name_temp[j] = '\0';
}
j = 0;
continue;
}
if((c1 >= '0' && c1 <= '9') || c1 == '.' || c1 == '\n')
{
continue;
}
if(flag)
{
name_temp[j++] = fp_line[i]; //存下汉字的字符。
}
}
}
printf("\n\n转化后的关系矩阵为:\n");
for(i = 0; i < name_number; i++)
{
for(j = 0; j < name_number; j++)
{
printf("%d ", relation[j][i]);
}
printf("\n");
}
max = 0;
c1 = 0;
flag = 0;
for(i = 0; i < name_number; i++) //遍历矩阵
{
c1 = 0;
for(j = 0; j < name_number; j++)
{
if(relation[j][i] == 1) //矩阵此位置为1,说明这一行的人选择了他当朋友
{
c1++;
}
}
if(c1 > max) //遍历一遍后,选择第flag列的人最多
{
max = c1;
flag = i;
}
if(c1 == 0) //c1为0说明本班没有选择他的人
{
printf("\n本班最自闭的人是:%s\n把他当成朋友的在本班一个都没有!\n", name[i]);
}
}
printf("\n本班最受欢迎的人是:%s\n把他当成朋友的有:%d人\n", name[flag], max);
return 0;
}