經典編程題目 運金 的幾種最優解的做法(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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章