March 2004 Green problems with analysis 未理解

 

March 2004 Green problems with analysis

Problem 1: Moo University - Team Tryouts [Brian Dean, 2001]
 
N (1 <= N <= 1,000) calves try out for the Moo U gymnastics team
this year, each with a positive integer height and a weight less
than 100,000.  Your goal is to select a team of as many calves as
possible from this group. There is only one constraint the team
must satisfy: the height H and weight W of each calf on the team
must obey the following inequality:
 
                A*(H-h) + B*(W-w) <= C
 
where h and w are the minimum height and weight values over all
calves on the team, and A, B and C are supplied positive integral
constants less than 10,000.   Compute the maximum number of calves
on the team.
 
PROBLEM NAME: tryout
 
INPUT FORMAT:
 
* Line 1: A single integer, N
 
* Line 2: Three space-separated integers, A, B and C
 
* Lines 3..N+2: Two space-separated integers: respectively the height
        and weight of a calf
 
SAMPLE INPUT (file tryout.in):
 
8
1 2 4
5 1
3 2
2 3
2 1
7 2
6 4
5 1
4 3
 
OUTPUT FORMAT:
 
* Line 1: One integer, the maximum number of calves on the team.
 
SAMPLE OUTPUT (file tryout.out):
 
5
 
OUTPUT DETAILS:
 
Calves 1, 2, 3, 4 and 7, for example, form a legal team. A larger team is
impossible.
 
ANALYSIS by Bruce Merry (South Africa) ==============================
 
The following simple algorithm will work, but will be too slow on
the big cases:
 
Loop over all weights and all heights in the set, and consider the
loop variables to be the minimum weight and height. In this, loop
over all cows and count the number that meet the minimum weight and
height and fit the constraint.
 
This is O(n^3), which will be too slow for N = 1000.
 
We can refine this algorithm by building things up. Suppose we fix minh
and loop through the possibilities for minw in increasing order. As
minw increases, the set of points satisfying the linear constraint gets
strictly bigger. If we sort the points by Ah + Bw, then they will
become valid points in the order they appear (valid in the sense of the
linear constraint, not relative to minw or minh). Thus we can use the
following algorithm:
 
- Loop over minh
  - Loop over minw in increasing order
    - add new points to the set of valid points, keeping track of the
      last one added (for next time round the loop)
    - compare the count to the best so far
    - remove the point corresponding to minw from the set
 
This is now an O(n^2) algorithm, easily fast enough.
 
======================================================================
 

2008 — Moo University – Team Tryouts

这道题USACO给的Analysis的方法很多人都没看懂,所以半形式化地证出来可能会有助于理解。在证明内容之前,先把AC的代码贴出来;在POJ上,316K141MS

#include <iostream>
#include <stdlib.h>
 
using namespace std;
 
struct Calf
{
    int h, w, mash, p;
};
 
int n, a, b, c;
Calf mash[1000];
Calf calf[1000];
int mark[1000];
 
int mash_comp(const void * a, const void * b)
{
    return ((Calf *) a)->mash - ((Calf *) b)->mash;
}
 
int calf_comp(const void * a, const void * b)
{
    return ((Calf *) a)->w - ((Calf *) b)->w;
}
 
int main()
{
    cin >> n;
    cin >> a >> b >> c;
 
    for (int i = 0; i < n; ++ i)
    {
        cin >> calf[i].h >> calf[i].w;
        calf[i].mash = calf[i].h * a + calf[i].w * b - c;
        calf[i].p = i;
    }
 
    qsort(calf, n, sizeof(Calf), calf_comp);
 
    for (int i = 0; i < n; ++ i)
    {
        mash[i] = calf[i];
        mash[i].p = i;
    }//calf拷贝到mash
 
    qsort(mash, n, sizeof(Calf), mash_comp);
 
    int ans = 0;
    for (int i = 0; i < n; ++ i)
    {
        memset(mark, 0, sizeof(mark));
        int k = 0, sum = 0;
        for (int j = 0; j < n; ++ j)
        {
            while (k < n && mash[k].mash <= calf[i].h * a + calf[j].w * b)
            {
                if (mash[k].h >= calf[i].h && mash[k].w >= calf[j].w)
                {
                    sum ++;
                    mark[mash[k].p] ++;
                }
                k ++;
            }
            ans = max(ans, sum);
            sum -= mark[j];
        }
        //assert(sum == 0);
    }
    cout << ans << endl;
 
    return 0;
}
 
 

下面的说明是对于上面代码的;在此之前需要清楚我们已经把 A*(H-h)+B*(W-w)≤C 展开并等价转化成 A*H+B*W-C≤A*h+B*w;同时你需要先阅读一下USACO的Analysis,因为下面的说明用到了其中的一些约定好的名称。

首先,如果没有mark[]参与运算,sum的值会高于真实值,因为当minw升高后,sum所统计的集合内会有某些元素的w<minw。为保持sum的性质(正确性),需要在每次升高minw之前,把那些因升高minw而不合法的元素去掉。

calf[]关于w是不减序列。当minw保持时,得到的解不会更优,因为在相同的minhminw下,新的解集中不包含之前具有相同minw的元素。这是约定好的,并且显然不会影响到最优解。

考虑当minw升高时,新的解集元素的w≥minw。记升高前的minww0minw>w0minw≥w0+1,升高minw后元素应满足w≥w0+1>w0。而原解集中w=w0的元素应当被去掉,则必须保证mark[j]会起到这个作用。

mark[j]的值仅取在{0, 1}内,即只标记着j所对应元素是否在新构成的解集内。当minw保持时,已说明解不会更优,其原因就在于当轮循环的minw被去掉。当minw升高时,去掉可能包含的最后一个元素,因之前的已经去掉了,于是要保持元素在失去被去掉的机会之前会被正确标记并处理。

mark[]增加的条件知 mash[k].w≥calf[j].w,即calf[mash[k].p].w≥calf[j].w,有mash[k].p≥j。每轮循环的mash[k].p都做了标记,最后去掉的只有j,故证。

以上,算法正确性得到证明。下面,简单说明为什么这个算法的时间复杂度是O(N2)。外层循环i枚举minh,为O(N);内层循环j,形式上亦得到O(N);再里面的那个while是干扰分析的主角,但要注意,循环执行的条件是“k<n”,也就是说这个循环最多只执行N次,循环k和循环j是并行的,所以依然是O(N)。因此得出最终的时间复杂度T = O(N2)

大概总结了一下,这道题大致需要记住两点吧。第一,多变元问题用冻结变量法;第二,将无序变为有序减少冗余。

最后,效仿一下;以上。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值