编程练习三(贪心算法)

A:Fence Repair

题目:

Farmer John wants to repair a small length of the fence around the pasture. He measures the fence and finds that he needs N (1 ≤ N ≤ 20,000) planks of wood, each having some integer length Li (1 ≤ Li ≤ 50,000) units. He then purchases a single long board just long enough to saw into the N planks (i.e., whose length is the sum of the lengths Li). FJ is ignoring the “kerf”, the extra length lost to sawdust when a sawcut is made; you should ignore it, too.

FJ sadly realizes that he doesn’t own a saw with which to cut the wood, so he mosies over to Farmer Don’s Farm with this long board and politely asks if he may borrow a saw.

Farmer Don, a closet capitalist, doesn’t lend FJ a saw but instead offers to charge Farmer John for each of the N-1 cuts in the plank. The charge to cut a piece of wood is exactly equal to its length. Cutting a plank of length 21 costs 21 cents.

Farmer Don then lets Farmer John decide the order and locations to cut the plank. Help Farmer John determine the minimum amount of money he can spend to create the N planks. FJ knows that he can cut the board in various different orders which will result in different charges since the resulting intermediate planks are of different lengths.

input

Line 1: One integer N, the number of planks
Lines 2.. N+1: Each line contains a single integer describing the length of a needed plank

output

Line 1: One integer: the minimum amount of money he must spend to make N-1 cuts

Sample input

3
8
5
8

Sample output

34

Hint

He wants to cut a board of length 21 into pieces of lengths 8, 5, and 8.
The original board measures 8+5+8=21. The first cut will cost 21, and should be used to cut the board into pieces measuring 13 and 8. The second cut will cost 13, and should be used to cut the 13 into 8 and 5. This would cost 21+13=34. If the 21 was cut into 16 and 5 instead, the second cut would cost 16 for a total of 37 (which is more than 34).

题目大意:

FJ需要修补牧场的围栏,他需要 N 块长度为 Li 的木头(N planks of woods)。开始时,FJ只有一块无限长的木板,因此他需要把无限长的木板锯成 N 块长度

为 Li 的木板,Farmer Don提供FJ锯子,但必须要收费的,收费的标准是对应每次据出木块的长度,比如说测试数据中 5 8 8,一开始,FJ需要在无限长的木板上锯下长度 21 的木板(5+8+8=21),第二次锯下长度为 5 的木板,第三次锯下长度为 8 的木板,至此就可以将长度分别为 5 8 8 的木板找出

题目可以转化为Huffman树构造问题 :

给定 N planks of woods,
1.  在 N planks 中每次找出两块长度最短的木板,然后把它们合并,加入到集合A中,
2. 在集合中找出两块长度最短的木板,合并加入到集合A中,重复过程,直到集合A中只剩下一个元素

显然,通过每次选取两块长度最短的木板,合并,最终必定可以合并出长度为 Sum(Li)的木板,并且可以保证总的耗费最少

我的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>

using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int maxn = 100;
int N,num;
long long sum;
int a,b, temp;

int main() {
   // freopen("input.txt", "r", stdin);
    priority_queue<int,vector<int>,greater<int> >q;
    scanf("%d",&N);
    sum = 0;
    for (int i = 0; i < N; i++) {
        scanf("%d",&num);
        q.push(num);
    }
    if (q.size()==1) {
        sum = q.top();
    }
    while(q.size()>1){
        a = q.top();
        q.pop();
        b = q.top();
        q.pop();
        temp = a + b;
        sum += temp;
        q.push(temp);
    }
    printf("%lld\n",sum);
    return 0;
}

B:Communication System

参考博客:
http://blog.chinaunix.net/uid-22263887-id-1778904.html

题目:

. We have received an order from Pizoor Communications Inc. for a special communication system. The system consists of several devices. For each device, we are free to choose from several manufacturers. Same devices from two manufacturers differ in their maximum bandwidths and prices.
By overall bandwidth (B) we mean the minimum of the bandwidths of the chosen devices in the communication system and the total price (P) is the sum of the prices of all chosen devices. Our goal is to choose a manufacturer for each device to maximize B/P.

Input

. The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by the input data for each test case. Each test case starts with a line containing a single integer n (1 ≤ n ≤ 100), the number of devices in the communication system, followed by n lines in the following format: the i-th line (1 ≤ i ≤ n) starts with mi (1 ≤ mi ≤ 100), the number of manufacturers for the i-th device, followed by mi pairs of positive integers in the same line, each indicating the bandwidth and the price of the device respectively, corresponding to a manufacturer

Output

. Your program should produce a single line for each test case containing a single number which is the maximum possible B/P for the test case. Round the numbers in the output to 3 digits after decimal point.

Sample Input

1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110

Sample Output

0.649

解题思路

题意:
要购买一套通讯系统,有一些设备组成,每个设备我们从一些制造商那里购得,带宽(bandwidth)是我们所选择的设备里面最小的带宽,总价格是我们选择的设备的总价格,我们的目标是求出最大的带宽和总价格的比值(B/P)。

思路:
一开始我就想用贪心,每种都选出拥有最大(B/P)的设备,后来发现不行。后来参考了网上的思路,先枚举带宽,再贪心选择价格最小的,最后求出结果。
具体是在输入时就找出所有这些设备中最小的带宽(low)和最大带宽(high)。然后从low递增到high,每个制造商里都选价格最小的设备,这样就能保证B/P最小了。其实还能优化,把每个带宽都记录下来枚举,这样在带宽大小相差较大的情况下可以省下很多时间,好像要用到STL里的set,暂时还不会,以后再说。

我的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int maxn = 100;
int T,n,m;
int i,j,k;
struct manufactor{
    int band;
    int price;
};
int mina,maxa;
int minprice,temppricesum;
double bp,maxbp;
manufactor a[105][105];
int loga[105];
int main() {
   // freopen("input.txt", "r", stdin);
    scanf("%d",&T);
    while(T--) {
        m = 0;
        maxbp = 0;
        mina = INF; maxa = 0;
        scanf("%d",&n);
        for (i =0; i < n; i++) {
            scanf("%d",&loga[m++]);
            for (j = 0; j <loga[m-1] ; j++) {
                scanf("%d %d",&a[i][j].band,&a[i][j].price);
                if (a[i][j].band < mina) {
                    mina = a[i][j].band;
                }
                if(a[i][j].band > maxa ){
                    maxa = a[i][j].band;
                }
            }
        }
        for (i = mina; i <= maxa; i++) {
            temppricesum = 0;
            for (j = 0; j < n; j++) {
                minprice = INF;
                for (k =0; k < loga[j]; k++) {
                    if ((a[j][k].band >= i) && (a[j][k].price< minprice) ) {
                        minprice = a[j][k].price;
                    }
                }
                temppricesum += minprice;
            }
            bp = (double)i / temppricesum;
            if (bp > maxbp) {
                maxbp = bp;
            }
        }
        printf("%.3f\n",maxbp);
    }
    return 0;
}

C:Tian Ji

参考博客:
http://blog.csdn.net/zhang20072844/article/details/8126344

题目:

田忌赛马的故事
田忌和国王打赌赛马,田忌和国王手上有相同数量的马,n匹马,一共要塞n场,每场要是田忌的马赢了,就赢200两银子,输入就输200两,打平就不得钱。
问怎样安排场次要是能赢可以使得田忌最后赢钱最多,要是输,能使田忌输的钱最少?

Sample Input

3
92 83 71
95 87 74
2
20 20
20 20
2
20 19
22 18
0

Sample Output

200
0
0

解题思路:

1,如果田忌的最快马快于齐王的最快马,则两者比。
(因为若是田忌的别的马很可能就赢不了了,所以两者比)
2,如果田忌的最快马慢于齐王的最快马,则用田忌的最慢马和齐王的最快马比。
(由于所有的马都赢不了齐王的最快马,所以用损失最小的,拿最慢的和他比)
3,若相等,则比较田忌的最慢马和齐王的最慢马
3.1,若田忌最慢马快于齐王最慢马,两者比。
(田忌的最慢马既然能赢一个就赢呗,而且齐王的最慢马肯定也得有个和他比,所以选最小的比他快得。)
3.2,其他,则拿田忌的最慢马和齐王的最快马比。
(反正所有的马都比田忌的最慢马快了,所以这匹马必输,选贡献最大的,干掉齐王的最快马)

我的代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int maxn = 100;
int T,n,m;
int i,j;
int tian[1005];
int king[1005];

int comp(const void *a ,const void *b){
    return  *(int*)a - *(int *)b;
}

int main() {
   // freopen("input.txt", "r", stdin);
    while(scanf("%d",&n)!=EOF && n){
        for (i = 0; i < n; i++) {
            scanf("%d", &tian[i]);
        }
        for (i = 0; i <n ; i ++) {
            scanf("%d", &king[i]);
        }
        qsort(tian, n, sizeof(int), comp);
        qsort(king, n, sizeof(int), comp);
        int maxt ,maxk,mint,mink;
        maxt = maxk = n-1;
        mint = mink = 0;
        int cnt = 0;
        int money = 0;
        while((cnt++) < n){
            if (tian[maxt] > king[maxk]) {
                money += 200;
                maxt--;
                maxk--;
            }else if (tian[maxt] < king[maxk]){
                money -= 200;
                mint++;
                maxk--;
            }else{
                if (tian[mint] > king[mink]) {
                    money += 200;
                    mint++;
                    mink++;
                }else{
                    if (tian[mint] < king[maxk]) {
                        money -= 200;
                        mint++;
                        maxk--;
                    }else{
                        mint++;
                        maxk--;
                    }

                }
            }
        }
        printf("%d\n",money);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值