经典编程题目 运金 的几种最优解的做法(C语言)

题目内容:某船最高载重量为300吨,现有重量为101,78,92,45,301,117,85,210的八块金子,在不超过最高载重的情况下,从中选择任意块金子使船运金重量达到最高。

做法一:二进制转化法

做法分析:现有8块金子,每块金子有两种情况:选用或者不选用,选用可以用1代表,不选用可以用0代表。这样的话从八块金字选用情况有:0000000111111111254种情况。最接近船载重的情况便是最优解。

#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;
}

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值