[USACO Training] Section 1.3

这一节的主题是贪心和枚举。个人认为不剪枝的叫枚举,剪枝的叫搜索。
适当的枚举是许多优秀的解法中必不可少的环节,通常,枚举的东西可以分为这样几类:选择、限制、答案。
1. 选择。基本就是根据题意模拟。
2. 限制。如果题目中有多种限制,我们可以枚举一种,检验是否满足其他限制。有时,答案也可以看作一种限制。
3. 答案。检查答案是否满足约束;如果答案具有单调性,可以二分。

TEXT Greedy Algorithm

Barn Repair [1999 USACO Spring Open]

有一些畜栏排成一列,有的需要覆盖木板。木板的尺寸不限,给定木板数量N,要求最小化覆盖的畜栏总量。

一种角度:从N到(N+1)

这是原文的角度。假设我们已经得到了(N-1)块木板的最优解,怎样扩展到N块木板?这个有点类似于动态规划。一种尝试是,我们要移走覆盖着最长非必要区间的那块板,换成两块,一个在那个区间的左边,一个在那个区间的右边。

我觉得原文的正确性证明不对。这种扩展方式是显然的,关键要证明最优子结构,即N的最优解包含(N-1)的最优解。我的水平还不够把这件事说清,但是,如果采取下面这种角度,一切都很显然。

另一种角度:反过来看

找到第一个必须被覆盖的畜栏和最后一个必须被覆盖的畜栏,问题等价于去掉(N-1)个非必须的区间,区间长度和尽可能大。因为每去掉一个区间,木板的总量增加1。这些区间是互不干扰的,于是取前(N-1)长的区间就好了。

Sorting a three-valued sequence [IOI 1996]

有一个序列,每个元素的取值范围是{1, 2, 3},求通过交换给它排序的最少步数。

算法:计算出1、2、3在有序情况下应该处于的区间。先还原一对对正好错位的元素,再还原所有还没归位的1,最后还原所有未归位的2。

同样不认可那个证明……但是自己也不会。

Friendly Coins - A Counter example [abridged]

探究什么条件下用贪心的策略换零钱是正确的是一个有趣的问题,不知道是否已经解决了。

Topological Sort

通过检查顶点的入/出度,更新,来拓扑排序。这是贪心吗?

PROB Mixing Milk

给定需要的牛奶量,每个农民可供应的牛奶量、每单位牛奶的价格,求满足需要的采购方案的最小代价。

排个序就好啦。ANALYSIS页面好多题解,其实就是两类:用快排的和用计数排序的。我用的是STL sort……

/*
ID: chrt2001
PROG: milk
LANG: C++
*/
#include <cstdio>
#include <algorithm>
using namespace std;
struct Farmer {
    int p, a;
    bool operator<(const Farmer& rhs) const
    {
        return p < rhs.p;
    }
} F[5000];
int main()
{
    freopen("milk.in", "r", stdin);
    freopen("milk.out", "w", stdout);
    int n, m, ans = 0;
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; ++i)
        scanf("%d %d", &F[i].p, &F[i].a);
    sort(F, F+m);
    for (int i = 0; n > 0; ++i) {
        int buy = min(n, F[i].a);
        ans += buy * F[i].p;
        n -= buy;
    }
    printf("%d\n", ans);
    return 0;
}

PROB Barn Repair

分析见前文。

这次我用了计数排序。

/*
ID: chrt2001
PROG: barn1
LANG: C++
*/
#include <cstdio>
#include <algorithm>
using namespace std;

bool O[201];
int S[199];

int main()
{
    freopen("barn1.in", "r", stdin);
    freopen("barn1.out", "w", stdout);  
    int m, s, c, mn = 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值