经典贪心算法
活动安排
n个活动共同使用一个报告厅,给出每个活动的起止时间(整数),如何安排才能使完成活动个数最多?
先开始最先结束的活动,为了留出更多的时间给其他活动。(最多安排活动个数唯一,但活动安排方案可能不唯一)
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 7;
struct Event {
int s;
int e;
int i;//活动编号
Event(int ss, int ee, int ii):s(ss),e(ee),i(ii){};
Event(){};
bool operator < (const Event& rhd)const {
return e < rhd.e;
}
};
int main()
{
int n;
cin >> n;
vector<Event> event;
for (int i = 0; i < n; ++i) {
int s, e;
cin >> s >> e;
event.push_back(Event(s, e, i));
}
sort(event.begin(), event.end());
// for (vector<Event>::iterator it = event.begin(); it != event.end(); ++it) {
// cout << "(" << it->s << ", " << it->e << ")" << endl;
// }//测试排序函数
vector<Event>::iterator it = event.begin();
//queue<Event> q;
//q.push(*it);
Event pre = *it++;
int cnt = 1;
for (; it != event.end(); ++it) {
if (it->s >= pre.e) {
//q.push(*it);
cnt++;
pre = *it;
}
}
cout << cnt << endl;
// while(!q.empty()) {
// cout << "(" << q.front().s << ", " << q.front().e << ")" << endl;
// q.pop();
// } //输出其中一种活动安排方案
return 0;
}
\
会场安排问题(<-这是测试连接),还是有n个活动,这n个活动必须都举办,问最少需要多少个会场才能满足要求?同样给出n个活动的起止时间(整数)。
小心同一时间既有活动开始,又有活动结束的情况
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
struct Point{
int time;
bool fg;
Point(int time, bool flag):time(time),fg(flag){};
Point(){};
bool operator < (const Point& rhd) const {
if (time < rhd.time)
return true;//若序化
if (time == rhd.time)
return !fg; //同一时间既有活动开始,又有活动结束,就先结束活动
return false;
}
};
vector<Point> pV; //点的动态数组容器
int greedy(vector<Point> pV) {
sort(pV.begin(), pV.end());
int maxV = 0, cnt = 0; //cnt表示同一时间时在进行的活动的个数
for (vector<Point>::iterator it = pV.begin(); it != pV.end(); ++it) {
if (it->fg) {
cnt++;
}
else cnt--;
maxV = max(maxV, cnt);
}
return maxV; //最多需要几个会场
}
int main()
{
int n;
while(~scanf("%d", &n)) {
int s, e;
for (int i= 0; i < n; ++i) {
scanf("%d%d", &s, &e);
pV.push_back(Point(s, true));
pV.push_back(Point(e, false));
}
int ans = greedy(pV);
printf("%d\n", ans);
pV.clear();
}
return 0;
}
百度之星2016的拍照那个问题,和会场安排非常相似,可见基础打好是多么重要。
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 20200;
int n;
struct Node {
int x, fg, d; //fg = 1, 左端点
Node(int x = 0, int fg = 0, int d = 0) : x(x), fg(fg), d(d) {}
bool operator < (const Node &tmp) const {
if (x != tmp.x) return x < tmp.x;
if (fg != tmp.fg) return fg > tmp.fg;
return d > tmp.d;
}
}e[N];
int ans[N];
int main()
{
int T, cas = 0, x, y, z, d;
scanf("%d", &T);
while (T--) {
int tot = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%d%d%d", &x, &y, &z, &d);
int l = y - z, r = x + z;
if (l <= r) { //在[l,r]可以观测到这条船
e[tot++] = Node(l, 1, d);
e[tot++] = Node(r, -1, d);
}
}
sort(e, e + tot);
int ret = 0, now = ans[tot] = 0;
for (int i = tot - 1; i >= 0; i--) {//向左方向行驶的船只
if (e[i].d == -1 && e[i].fg == -1) ++now;
ans[i] = max(ans[i + 1], now);
if (e[i].d == -1 && e[i].fg == 1) --now;
}
for (int i = 0; i < tot; i++) if (e[i].d == 1) { //向右方向行驶的
if (e[i].fg == 1) now++;
ret = max(ret, now + ans[i]);
if (e[i].fg == -1) now--;
}
printf("Case #%d:\n%d\n", ++cas, ret);
}
return 0;
}
\
汽车加油问题(我在网上没有找到OJ试题,所以代码没有验证)
一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应
在哪些加油站停靠加油,使沿途加油次数最少。对于给定的n(n <= 5000)和k(k <= 1000)个加油站位置,编程计算最少加油次数。并证明算法能产生一个最优解。
要求:
输入:第一行有2个正整数n和k,表示汽车加满油后可行驶n公里,且旅途中有k个加油站。接下来的1 行中,有k+1 个整数,表示第k个加油站与第k-1 个加油站之间的距离。第0 个加油站表示出发地,汽车已加满油。第k+1 个加油站表示目的地。
输出:输出编程计算出的最少加油次数。如果无法到达目的地,则输出”NoSolution”。
#include <stdio.h>
#include <string.h>
#define N 10007
int ary[N];
bool vis[N];
int main()
{
int i, n, k; //加满油行驶k千米,k个加油站,第k + 1个数是目的地
while(~scanf("%d%d", &n, &k)) {
ary[0] = 0;
memset(vis, 0, sizeof(vis));
bool fg = true;
for (i = 1; i <= k + 1; ++i) {
scanf("%d", ary + i);
if (ary[i] > n) {
fg = false;
}
} //ary[k + 1]是目的地,ary[i]表示第i-1和第i个加油站间的距离
if (fg == false) {
puts("No Solution");
continue;
}
int cnt = 0, amount = n;
for (i = 1; i <= k; ++i) { //每次迭代判断第i个加油站是否要停下加油
if (ary[i] + ary[i + 1] <= amount) {
amount -= ary[i];
}
else {
cnt++;
amount = n;
vis[i] = true;//在第i个车站停下加油
}
}
printf("%d\n", cnt);
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
string str;
while(cin >> str) {
int k;
cin >> k;
int cnt = str.length() - k; //cnt为最小数的位数
string ans;
string::iterator left = str.begin(), right = str.end() - cnt + 1, it;
while(cnt--) {
it = min_element(left, right);
ans.append(1, *it);
left = it + 1;
right++;
}
//删除前导0,第三个参数不用写it++,若有删除,it就指向新的字字母了
for (it = ans.begin(); it != ans.end() && *it == '0';)
ans.erase(it);
if (ans.length() == 0)
ans = "0";
cout << ans << endl;
}
return 0;
}
\
\
下面的贪心算法无关,就是郑大OJ1003一道题,判断一个(可能超级大的数)数是否是17的倍数。
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
BigInteger num, tmp = new BigInteger ("17");
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
num = sc.nextBigInteger();
if (num.equals(BigInteger.ZERO))
break;
num = num.mod(tmp);
if(num.equals(BigInteger.ZERO)){
System.out.println("1");
}
else {
System.out.println("0");
}
}
sc.close();
}
}
java / C++
#include <stdio.h>
int main()
{
char str[105], i;
while(~scanf(" %s", str) && str[0] != '0') {
int sum = 0;
for (i= 0; str[i]; ++i) {
sum = (sum * 10 + str[i] - '0') % 17;
}
printf("%d\n", (sum == 0 ? 1 : 0));
}
return 0;
}
\
\
\
\
\