題目內容:某船最高載重量爲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;
}