# 贪心算法题型总结

### 题1 POJ - 2940

#### 题目描述

As you may know from the comic “Asterix and the Chieftain’s Shield”, Gergovia consists of one street, and every inhabitant of the city is a wine salesman. You wonder how this economy works? Simple enough: everyone buys wine from other inhabitants of the city. Every day each inhabitant decides how much wine he wants to buy or sell. Interestingly, demand and supply is always the same, so that each inhabitant gets what he wants.

There is one problem, however: Transporting wine from one house to another results in work. Since all wines are equally good, the inhabitants of Gergovia don’t care which persons they are doing trade with, they are only interested in selling or buying a specific amount of wine. They are clever enough to figure out a way of trading so that the overall amount of work needed for transports is minimized.

In this problem you are asked to reconstruct the trading during one day in Gergovia. For simplicity we will assume that the houses are built along a straight line with equal distance between adjacent houses. Transporting one bottle of wine from one house to an adjacent house results in one unit of work.

Input

The input consists of several test cases.

Each test case starts with the number of inhabitants n (2 ≤ n ≤ 100000). The following line contains n integers ai (−1000 ≤ ai ≤ 1000). If ai ≥ 0, it means that the inhabitant living in the ith house wants to buy ai bottles of wine, otherwise if ai < 0, he wants to sell −ai bottles of wine. You may assume that the numbers ai sum up to 0.

The last test case is followed by a line containing 0.

Output

For each test case print the minimum amount of work units needed so that every inhabitant has his demand fulfilled. You may assume that this number fits into a signed 64-bit integer (in C/C++ you can use the data type “long long” or “__int64”, in JAVA the data type “long”).

Sample Input：

5
5 -4 1 -3 1
6
-1000 -1000 -1000 1000 1000 1000
0

Sample Output：

9
9000

#### 解题思路

1.路费与路程成正比，那么路程越近越好；我们来假设前3户人家A家, B家, C家分别为 +3， +2 ， -1 ；那么A直接给C ， 与A先寄存给B（假设寄存一样要路费），再给C，路费分别为 1(酒数量) * 2 (路程) = 2和 1 * ( 1 + 1) = 2，那么如果买家要找一个最近的卖家，那我们无需考虑究竟这个卖家在哪里，只需要一直寄存过去，直到买卖数量抵消。
2.问题那么就简化为，相当于无论是买酒或是卖酒，只需与相邻的人买卖，不够可以欠着；

3.每次路程为1，买卖酒数量为当前这一家的数量。
4.在递推酒数量的过程中，相当于已经递推了路程。

#### 代码解析


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int n,i;
int a[100000] = {0};

while (scanf("%d",&n) != EOF && n != 0) {
long long int sum = 0;
for (i = 0; i < n; i++)
scanf("%d",&a[i]);

for (i = 0; i < n; i++) {
a[i+1] += a[i];
sum += (long long int)(abs(a[i]));
}
printf("%lld\n",sum);
}
return 0;
}


### 题2 HDU - 1009

#### 题目描述

FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean.
The warehouse has N rooms. The i-th room contains J[i] pounds of JavaBeans and requires F[i] pounds of cat food. FatMouse does not have to trade for all the JavaBeans in the room, instead, he may get J[i]* a% pounds of JavaBeans if he pays F[i]* a% pounds of cat food. Here a is a real number. Now he is assigning this homework to you: tell him the maximum amount of JavaBeans he can obtain.

Input
The input consists of multiple test cases. Each test case begins with a line containing two non-negative integers M and N. Then N lines follow, each contains two non-negative integers J[i] and F[i] respectively. The last test case is followed by two -1’s. All integers are not greater than 1000.

Output
For each test case, print in a single line a real number accurate up to 3 decimal places, which is the maximum amount of JavaBeans that FatMouse can obtain.

Sample Input
5 3
7 2
4 3
5 2
20 3
25 18
24 15
15 10
-1 -1

Sample Output
13.333
31.500

#### 代码解析

#include <stdio.h>
struct a
{
double j;
double f;
double k;

};

int main()
{
int m,n,i,j;
struct a tmp;
struct a tr[10000];

while (scanf("%d %d",&m,&n) != EOF && m != -1 && n != -1) {
for (i = 0; i < n; i++) {
scanf("%lf %lf",&tr[i].j,&tr[i].f);
tr[i].k = tr[i].j/tr[i].f;
}

for (i = 0; i < (n-1); i++) {
for (j = 0; j < (n-1-i); j++) {
if (tr[j].k < tr[j+1].k) {
tmp = tr[j];
tr[j] = tr[j+1];
tr[j+1] = tmp;
}
}
}
double sum = 0;
for (i = 0; i < n; i++) {
if ( (m - tr[i].f) > 0) {
sum += tr[i].j;
m -= tr[i].f;
} else{
sum += ((double)m/tr[i].f)*tr[i].j;
break;
}
}
printf("%0.3f\n",sum);
}
return 0;
}

### 题3 HDU - 2089

#### 题目描述

62315 73418 88914

Input

#### 代码解析

#include <stdio.h>

int main()
{
int a[1000000] = {0};
long int i;
for (i = 0; i < 1000000; i++) {
long int m = i,k = i;
while (m) {
if (m%10 == 4) {
a[i] = 1;
break;
}
m /= 10;
}
while (k) {
if (k%100 == 62) {
a[i] = 1;
break;
}
k /= 10;
}
}
long int w,r;
while (scanf("%ld %ld",&w,&r) != EOF && ( w != 0 || r != 0) ) {
long int count = 0;
for (i = w; i <= r; i++) {
if (a[i] == 0) {
count++;
}
}
printf("%ld\n",count);
}
return 0;
}

### 题4 HDU - 2037

“今年暑假不AC？”
“是的。”
“那你干什么呢？”
“看世界杯呀，笨蛋！”
“@#\$%^&*%…”

Input

Output

Sample Input

12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0

Sample Output
5

#### 解题思路

1.若按开始时间排序，肯定无法获得最优解，因为我们无法避免这样一种情况：开始的最早，结束的最晚，一天下来可能只能看一两个节目；
2.于是我们按结束时间从小到大排序，当一个节目结束，找到离它结束时间最近的一个节目（因为是符合时间里面的 最近一个节目，所以它与同期节目相比，一定是结束的最早的，时间可以用来看更多的节目），发现能获得最优解。（这里排序没用结构体，推荐还是用结构体…）

#### 代码解析

#include<stdio.h>
int main(int argc, const char * argv[]) {

int i,n,j;

int tmp;

while (scanf("%d",&n) != EOF && n != 0) {

int count = 1;
int a[100] = {0};
int b[100] = {0};
for (i = 0; i < n; i++)
scanf("%d %d",&a[i],&b[i]);

for (i = 0; i < (n-1); i++) {
for (j = 0; j < (n-1-i); j++) {
if (b[j] > b[j+1]) {
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;

tmp = b[j];
b[j] = b[j+1];
b[j+1] = tmp;
}
}
}

i = 0;
for (j = 1; j < n; j++) {
if (a[j] >= b [i]){
i = j;
count++;
}
}
printf("%d\n",count);
}
return 0;
}


### 题5 HDU - 5055

#### 题目描述

Bob and math problem

Recently, Bob has been thinking about a math problem.
There are N Digits, each digit is between 0 and 9. You need to use this N Digits to constitute an Integer.
This Integer needs to satisfy the following conditions:
1. must be an odd Integer.
2. there is no leading zero.
3. find the biggest one which is satisfied 1, 2.

Example:
There are three Digits: 0, 1, 3. It can constitute six number of Integers. Only “301”, “103” is legal, while “130”, “310”, “013”, “031” is illegal. The biggest one of odd Integer is “301”.

Input

There are multiple test cases. Please process till EOF.
Each case starts with a line containing an integer N ( 1 <= N <= 100 ).
The second line contains N Digits which indicate the digita1,a2,a3,⋯,an.(0≤ai≤9)

Output

The output of each test case of a line. If you can constitute an Integer which is satisfied above conditions, please output the biggest one. Otherwise, output “-1” instead.

Sample Input
3
0 1 3
3
5 4 2
3
2 4 6

Sample Output
301
425
-1

#### 解题思路

（这题输出正确的数不难，难的是对前面各种情况的判断）

#### 代码解析

#include <stdio.h>

int main()
{
int n,i,j,tmp,count;
int a[100] = {0};
int flag = 0;
int flag1 = 0,flag2 = 0;
while (scanf("%d",&n) != EOF) {
flag = 0;
flag1 = 0;
flag2 = 0;

for ( i = 0; i < n; i++)
scanf("%d",&a[i]);

for (i = 0; i < n; i++)
if (a[i] % 2 == 1) flag1++;

for (i = 0; i < n; i++)
if (a[i] != 0) flag2++;

if ((flag1 == 1 && flag2 == 1 && n != 1) || (flag1 == 0)) {
printf("-1\n");
continue;

}

tmp = 10;
count = 0;
flag = 0;
for (i = 0; i < n; i++) {
if ( (a[i] % 2 == 1) && (a[i] < tmp) ) {
tmp = a[i];
count = i;
flag = 1;
}
}

if (flag == 1) {
a[count] = a[n-1];
a[n-1] = tmp;
}

for (i = 0; i < (n-2); i++) {
for (j = 0; j < (n-2-i); j++) {
if (a[j] < a[j+1]) {
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
}
}
}

for (i = 0; i < n; i++)
printf("%d",a[i]);

printf("\n");
}
return 0;
}

### 题6 HDU - 1789

#### 题目描述

Doing Homework again

Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test. And now we assume that doing everyone homework always takes one day. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.

Input

The input contains several test cases. The first line of the input is a single integer T that is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=1000) which indicate the number of homework.. Then 2 lines follow. The first line contains N integers that indicate the deadlines of the subjects, and the next line contains N integers that indicate the reduced scores.

Output
For each test case, you should output the smallest total reduced score, one line per test case.

Sample Input
3
3
3 3 3
10 5 1
3
1 3 1
6 2 3
7
1 4 6 4 2 4 3
3 2 1 7 6 5 4

Sample Output
0
3
5

#### 解题思路

1.先按分数由大到小排序，分数相同时，按时间由小到大排序，于是我们按这个排序去处理，会先处理分数大的；
2.创建一个数组，初始化为0。以每一对数的截止日期为下标，将数组中的内容改为1（有数为1，无数为0）；
3.但是很显然，我们还不能直接按这个排序，将所有数直接输入数组中，因为有一些数的截止日期相同，那如何来处理截止日期相同的情况？
4.当遇到数组中内容为1的情况时，说明有一个与你截止日期相同，但分数更大的数已经占据了这个位置，那我们从在数组中，以这个截止日期为下标往前找，当找到空位时，将数字填入（把0改为1）。如果找不到空位，将分数累计，最后输出。
5.思想与哈希表中开放寻址法解决冲突的思想类似。

#### 代码解析

#include <stdio.h>

struct _homework{
int scorce;
};

int main()
{
struct _homework homew[1000];
struct _homework tmp;
int T,N;
int i,j,k;
int m;

scanf("%d",&T);

for (m = 0; m < T; m++) {

scanf("%d",&N);
for (j = 0; j < N; j++)

for (j = 0; j < N; j++)
scanf("%d",&homew[j].scorce);

for (j = 0; j < N-1; j++) {
for (k = 0; k < N-1-j; k++) {
if (homew[k].scorce < homew[k+1].scorce) {
tmp = homew[k];
homew[k] = homew[k+1];
homew[k+1] = tmp;

}  else if (homew[j].scorce == homew[j+1].scorce) {
tmp = homew[j];
homew[j] = homew[j+1];
homew[j+1] = tmp;
}
}
}
}
int a[1001] = {0};
int sum = 0;
for (i = 0; i < N; i++) {
if ( a[homew[i].deadline] == 0 )
else{
int flag = 0;
for (; j >= 1; j--) {
if (a[j] == 0){
a[j] = 1;
flag = 1;
break;
}
}
if (flag == 0)
sum = sum + homew[i].scorce;
}
}
printf("%d\n",sum);
}
return 0;
}

### 题7 HDU - 6188

#### 题目描述

Duizi and Shunzi

Nike likes playing cards and makes a problem of it.

Now give you n integers, ai(1≤i≤n)
We define two identical numbers (eg: 2,2) a Duizi, and three consecutive positive integers (eg: 2,3,4) a Shunzi.
Now you want to use these integers to form Shunzi and Duizi as many as possible.
Let s be the total number of the Shunzi and the Duizi you formed.
Try to calculate max(s)max(s).
Each number can be used only once.

Input
The input contains several test cases.
For each test case, the first line contains one integer n(1≤n≤106).
Then the next line contains n space-separated integers a (1≤ai≤n)

Output
For each test case, output the answer in a line.

Sample Input
7
1 2 3 4 5 6 7
9
1 1 1 2 2 2 3 3 3
6
2 2 3 3 3 3
6
1 2 3 3 4 5

Sample Output
2
4
3
2

#### 解题思路

1.将所有牌放入一个数组中，当然不是直接放入，而是把牌的点数作为数组下标，例如，有1张5点的牌，则数组中下标为5的空间，存放1；有3张6点的牌，则数组中下标为6的空间，存放3；
2.顺子需要三张牌，对子只需要两张，所以我们尽量多组对子；3.当牌数>2时，不难发现，这些牌尽量先组对子，剩下两张牌再具体讨论；
4.当牌数<=2时，我们需要分情况讨论，到底是组顺子好还是组对子好；
5.当牌数为偶数张，直接组对子，假如这时候有两张，我们已经能组成一对了，但是如果考虑去组顺子的话，需要后面两张也都有牌（即使有牌，也不会大于组对子能组成的数量）；
6.当牌数为奇数，且下一张也为奇数，第三张有牌时才考虑去组顺子。

#### 代码解析

#include <stdio.h>

long int k[1000000] = {0};

int main()
{
long int n,i,d,count;
while (scanf("%ld",&n) != EOF) {
count = 0;
for ( i = 0; i < n; i++) {
scanf("%ld",&d);
k[d]++;
}
for (i = 1; i < 1000000; i++) {
if (k[i]%2 == 0)
count += k[i]/2;
else if (k[i]%2 == 1 && k[i+1]%2 == 1 && k[i+2] > 0) {
count += (1 + k[i]/2 + k[i+1]/2 );
k[i+2]--;
i++;
}
else {
count += (k[i]/2 + k[i+1]/2);
i++;
}
}
printf("%ld\n",count);
for (i = 1; i < 1000000; i++)
k[i] = 0;
}
return 0;
}

### 题八 POJ - 1700

#### 题目描述

Crossing River

A group of N people wishes to go across a river with only one boat, which can at most carry two persons. Therefore some sort of shuttle arrangement must be arranged in order to row the boat back and forth so that all people may cross. Each person has a different rowing speed; the speed of a couple is determined by the speed of the slower one. Your job is to determine a strategy that minimizes the time for these people to get across.

Input
The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. The first line of each case contains N, and the second line contains N integers giving the time for each people to cross the river. Each case is preceded by a blank line. There won’t be more than 1000 people and nobody takes more than 100 seconds to cross.

Output
For each test case, print a line containing the total number of seconds required for all the N people to cross the river.

Sample Input
1
4
1 2 5 10

Sample Output
17

#### 解题思路

1.最快的和次快的过河,然后最快的将船划回来;次慢的和最慢的过河,然后次快的将船划回来
2.最快的和最慢的过河,然后最快的将船划回来,最快的和次慢的过河,然后最快的将船划回来

#### 代码解析

#include <iostream>
using namespace std;

int main()
{
int a[1000], t, n, sum;
scanf("%d", &t);
while(t--) {
scanf("%d",&n); // n个人
sum = 0; // 时间总和

for(int i = 0; i < n; ++i)
scanf("%d",&a[i]);

//重复上述两种方法,该方法每次循环运送两个人,则时间根据最小的进行叠加
while(n > 3) {
// 最快的和次快的过河,然后最快的将船划回来;次慢的和最慢的过河,然后次快的将船划回来
sum += min(a[1] + a[0] + a[n - 1] + a[1],
// 最快的和最慢的过河,然后最快的将船划回来,最快的和次慢的过河,然后最快的将船划回来
a[n - 1] + a[0] + a[n - 2] + a[0]);
n -= 2;
}
if(n == 3)
sum += a[0] + a[1] + a[2]; //当人数为三时。两种方法都只剩 0 1 2 了
else if(n == 2)
sum += a[1];
else
sum += a[0];

printf("%d\n",sum);
}
}

### 题九 POJ1328

#### 题目描述

Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.
We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.

Input

The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases.
The input is terminated by a line containing pair of zeros

Output

For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. “-1” installation means no solution for that case.

Sample Input

3 2
1 2
-3 1
2 1

1 2
0 2

0 0

Sample Output

Case 1: 2
Case 2: 1

#### 解题思路

(注意，由于懒所以这并不是最终的AC代码，而是解题思路，所以输入输出格式没有按照题目要求来，也没有分组计算)

#### 代码解析

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

struct Point {
double sta;
double end;
} point[1000];

int cmp(const Point& a, const Point& b) {
return a.sta > b.sta ? 1 : -1;
}

int main()
{
int n, d; // 海岛个数、雷达半径
cin >> n >> d;
int counting = 1; // 所需个数

for(int i = 0; i < n; ++i) {
int x, y;
cin >> x >> y;
// 超出范围
if(y > d)
counting = -1;

double t = sqrt(d * d - y * y);

//转化为最少区间的问题
//区间左端点
point[i].sta = x - t;
//区间右端点
point[i].end = x + t;
}

//按区间左端点排序
if (counting != -1)
sort(point, point + n, cmp);

//区间起始右端点
double s = point[0].end;

for(int i = 1; i < n; ++i) {
if (point[i].sta > s) {
//如果两个区间没有重合,增加雷达数目并更新右端点
++counting;
}
s = point[i].end;
}
cout << counting << endl;
system("pause");
return 0;
} 

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120