zoukankan      html  css  js  c++  java
  • [USACO 2012 Feb G]Cow Coupons----贪心&带悔(看完稳AC)

    在这里插入图片描述
    输入:

    4 1 7
    3 2
    2 2
    8 1
    4 3
    

    输出:

    3
    

    提示:
    FJ has 4 cows, 1 coupon, and a budget of 7.FJ uses the coupon on cow 3 and buys cows 1, 2, and 3, for a total cost of 3 + 2 + 1 = 6.

    意思是有n头牛,现在有k张优惠券以及m元,每头牛有一个原始价格和折扣价格,问最多能买多少牛

    一开始的方法很简单,由于题目里面说了折扣价格一定比原始价格便宜,所以说首先按照折扣价格从小大大进行排序,将前k个牛的花费看作是折扣之后的价格,而将后面的花费看作是原始价格,然后重新将价值从小到大进行排序,尽可能的多选
    然后交了一发之后ac
    其实是错的
    Wrong_code:

    ll n, m, k;
    struct node {
        int p, c;
        int flag;
        int val;
    } a[maxn];
    bool cmp(node a, node b) {
        return a.c < b.c;
    }
    bool cmp2(node a, node b) {
        return a.val < b.val;
    }
    int main() {
        n = read, k = read, m = read;
        for (int i = 1; i <= n; i++) {
            a[i].p = read, a[i].c = read;
            a[i].flag = 0;
        }
        sort(a + 1, a + 1 + n, cmp);
        for (int i = 1; i <= n; i++) {
            if (i <= k)
                a[i].val = a[i].c;
            else
                a[i].val = a[i].p;
        }
        ll sum = 0;
        sort(a + 1, a + 1 + n, cmp2);
        for (int i = 1; i <= n; i++) {
            sum += a[i].val;
            if(sum > m){
                printf("%d
    ",i-1);
                return 0;
            }
        }
        cout << n <<endl;
        return 0;
    }
    /**
     
     
    **/
    

    没想到这个错误的代码在牛课上竟然ac
    在这里插入图片描述
    码完这个代码之后,突然被同学hack了
    给了一组样例:

    2 1 5
    3 1
    1000 2
    

    应该是2才是,可惜我的结果是1
    像这样的数据点有的是,在牛客后台也有很多错误的代码
    比如向上面的这个样例,我们应该还要维护一个大根堆,将选择的优惠差值放在里面,考虑是不是可以将用过券的牛不用了,反悔掉,然后用到另一头牛上
    然后写了一手交了亿发:
    在这里插入图片描述
    还是错误代码:

    ll n, m, k;
    struct node {
    	ll p, c;
    } a[maxn];
    bool cmp(node a, node b) {
    	return a.c < b.c;
    }
    bool cmp2(node a, node b) {
    	return a.p < b.p;
    }
    priority_queue<ll> que;
    int main() {
    	n = read, k = read, m = read;
    	for (int i = 1; i <= n; i++) {
    		a[i].p = read, a[i].c = read;
    	}
    	sort(a + 1, a + 1 + n, cmp);
    	ll sum = 0;
    	for (int i = 1; i <= k; i++) {
    		sum += a[i].c;
    		if(sum > m) {
    			printf("%d
    ",i-1);
    			return 0;
    		}
    		que.push(a[i].p - a[i].c);
    	}
    	//
    	if(k == n) {
    		printf("%lld
    ",n);
    		return 0;
    	}
    	sort(a + 1 + k, a + 1 + n, cmp2);
    	for (int i = k + 1; i <= n; i++) {
    		ll sub = a[i].p - a[i].c;
    		if(sub > que.top()) {
    			sum += que.top();
    			que.pop();
    			que.push(sub);
    			sum += a[i].c;
    		} else sum += a[i].p;
    		if(sum > m) {
    			printf("%d
    ",i-1);
    			return 0;
    		}
    	}
    	cout << n <<endl;
    	return 0;
    }
    

    然后想了个错误数据:

    3 2 6
    2 1
    1000 3
    5 1
    

    结果应该是3才是,可惜我得出2
    方案是优惠购买后两个,花费4,原始价格购买第一个,花费为6

    对于上面的错误代码我们可以看到:
    在这里插入图片描述
    开始花费为2,买了两个折扣后为1的,然后进入之后,第三个物品可以优惠997,然后将优惠4的取消使用优惠券,加上差值之后变成了6,然后又买了折扣价值为3的物品,此时相当于给2 1物品以及1000 3物品使用了优惠券,其实是应该对1000 3和5 1使用优惠券
    所以说这个代码是错的!!!而且很多晚上的代码都用了这种方法
    在看博客的时候一定要审慎的看待这些代码,要有批判的眼光去学习

    正确思路
    首先我们将n头牛按照折扣价值从小到大进行排序
    然后选折扣价值里面最小的k个进行求和,如果连折扣后的最小的k个都买不了的话,直接判断下进行输出i-1,在处理值的过程中加和记录sum,并且将优惠的价格放到小根堆里进行维护(que)

    然后我们考虑剩下的n-k头牛是否可以替换掉已经用券的k头牛中的一部分

    2 1 5
    3 1
    1000 2
    

    比如在这个样例中,我们开始选择的是折扣价格为1的这头牛
    然后将剩下的n-k头牛的原始价格和折扣价格分别放到小根堆里进行维护queP,queC
    每次选取的时候,如果说优惠的最小的价格 + 当前优惠的价格甚至小于未进行优惠的最小价格,那么说明就可以替换掉
    这时候就要把之前在前k头牛里面的折扣弥补回来 sum += que.top()
    弥补之后,还要附上当前折扣之后的价格queC.top()
    然后记得pop&&push相应的价值
    具体代码如下:
    AC_code:

    typedef pair<int,int> PII;
    ll n, m, k;
    struct node {
    	ll p, c;
    } a[maxn];
    bool cmp(node a, node b) {
    	return a.c < b.c;
    }
    bool vis[maxn];
    priority_queue<int, vector<int>, greater<int> > que;
    priority_queue<PII,vector<PII>,greater<PII> >queP,queC;
    int main() {
    	n = read, k = read, m = read;
    	for (int i = 1; i <= n; i++) {
    		a[i].p = read, a[i].c = read;
    	}
    	sort(a + 1, a + 1 + n, cmp);
    	ll sum = 0;
    	for (int i = 1; i <= k; i++) {
    		sum += a[i].c;
    		if(sum > m) {
    			printf("%d
    ",i-1);
    			return 0;
    		}
    		que.push(a[i].p - a[i].c);
    	}
    	for(int i=k+1; i<=n; i++) {
    		queP.push({a[i].p,i});
    		queC.push({a[i].c,i});
    	}
    //	debug(sum);
    	for(int i=k+1; i<=n; i++) {
    		while(vis[queC.top().second]) queC.pop();
    		while(vis[queP.top().second]) queP.pop();
    		int p1 = queC.top().second;
    		int p2 = queP.top().second;
    		int t1 = queC.top().first;
    		int t2 = queP.top().first;
    		t1 += que.top();
    //		debug(p1);
    //		debug(p2);
    //		debug(t1);
    //		debug(t2);
    		if(t1 < t2) {
    			sum += t1;
    			queC.pop();
    			que.pop();
    			que.push(a[p1].p - a[p1].c);
    			vis[p1] = 1;
    		} else {
    			sum += t2;
    			queP.pop();
    			vis[p2] = 1;
    		}
    //		cout << sum <<endl;
    		if(sum > m) {
    			printf("%d
    ",i-1);
    			return 0;
    		}
    	}
    	cout << n <<endl;
    	return 0;
    }
    /**
    3 2 6
    2 1
    1000 3
    5 1
    
    4 2 8
    1001 4
    1001 4
    4 4
    4 4
    
    **/
    

    洛谷牛客很多代码都是错的,错误代码都能AC,稍感无语

  • 相关阅读:
    test
    封装和构造方法
    面向对象
    数组的排序
    UDP编程(八)
    多的是面向对象你不知道的事
    面向对象组合的使用
    类成员的进一步阐述
    面向对象初始
    吾日三省吾身
  • 原文地址:https://www.cnblogs.com/PushyTao/p/15459818.html
Copyright © 2011-2022 走看看