ZOJ 3715 Kindergarten Election【枚举+贪心】

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3715

题意:

通过贿赂别人来增加自己的选票,最少要多少糖果才能让自己的选票最多;

思路:我之前的一篇博客有一道类似的题目,代码也基本上是一样的,我这里就不重复说了,下面是链接

https://blog.csdn.net/godleaf/article/details/81609111

这里讲讲一个比较关键的问题就是自己也要选除自己以外的人,要怎么处理;我一开始的思路就是找出票数最少的人,然后把票给他就行了;但是就是因为这个,WA了数次;事实上,自己的这一票可以不做处理,为什么?首先,自己的这一票不管投给谁,都不影响所有票数的最大值,也就是说,肯定存在一个人的选票,即使+1也不会比最大选票的那个人的票数高;这里自己在纸上模拟几个例子就能明白,我们之所以会考虑1这一票选谁这个问题,肯定是以为有可能加上这一票,最大票数会改变;如果不影响最大值,我们也没必要去考虑1选谁这个问题,但是,如果你是按照我之前博客写的那种方法去做这道题的话,就有可能不是最优结果(在网上,其实有很多人的AC代码里面也都没有考虑自己选谁这个问题,都是直接忽略了);

我们来看一下这个图:假设有 4个人,上面是 2,3,4的票数,红色的表示1投的票,其他蓝色都是除1以外的人投的票,最初1先不投票,那么对应的票数是  2有1票,3有1票,4有2票,按照上面的思路,找出票数最少的,然后把自己的票给那个票数最少的人,显然这里有两个票数最少的,假设我们投给2,2就多了一个红色的方块;那么票数最大值是2,我们最先枚举1得到3票的花费,显然就是从小到大的花费一次累加3次就行了;如果1要想票数为2,就能是所有选票最大,我们就看看有没有票数是大于或者等于2的,显然2和4都是2,那么我们会优先取比1票数大或者等于的票,得到的结果就是  20+10,但是如果我们当初把1这票给3的话,结果会如果? 把红色方格给3,那么就会优先取3和4的票,那么结果就 10+10;这就是导致答案不正确的地方;

这个小细节很难被发现,如果在有限的比赛的话,就格外吃亏;下次调试的时候,尽量多留意这些不唯一的选择,就像上面的情况,找出票数最小的,把自己的票给他这个思路本身是符合逻辑的,但是也可能出现多个最小值,如果下次你发现了这种不唯一的情况,就一定要多问问自己,不唯一的情况下,我选任意一个会不会出现不一样的结果?

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(0);

typedef long long ll;
const int Maxn = 110;
const long long LINF = 1e18;
const int INF = 0x3f3f3f3f;

struct point {
    int p,cost;
} a[Maxn];

int vis[Maxn],mn,mi,M;

bool cmp (const point &a1, const point &a2) {
    return a1.cost < a2.cost;
}

int main (void)
{
    IOS
    int t,n,x[Maxn],y[Maxn];
    cin >> t;
    while (t--) {
        cin >> n;
        memset(vis,0,sizeof(vis));
        for (int i = 2; i <= n; ++i) {
            cin >> x[i];
            vis[x[i]]++;
        }
        M = 0;
        for (int i = 2; i <= n; ++i) {
            cin >> y[i];
            if(x[i] != 1) {
                a[++M].p = x[i];
                a[M].cost = y[i];
            }
        }
        mn = 0; 
       
        for (int i = 2; i <= n; ++i) mn = max(mn,vis[i]);
        if(vis[1] > mn) { cout << "0" << endl; continue; }
        sort(a+1,a+M+1,cmp);
        int tmp[Maxn],used[Maxn],res,ans = INF;
        for (int i = mn; i > 0; --i) {
                res = 0;
                memset(used,0,sizeof(used));
                for (int j = 1; j <= n; ++j) tmp[j] = vis[j];
                for (int j = 1; j <= M; ++j) {
                    if(tmp[a[j].p] > i) {
                        tmp[a[j].p]--; tmp[1]++;
                        res+=a[j].cost;
                        used[j] = 1;
                    }
                }
                for (int j = 1; tmp[1] <= i && j <= M; ++j) {
                    if(!used[j]) {
                        tmp[1]++;
                        res+=a[j].cost;
                    }
                }
                if(tmp[1] > i) ans = min (ans, res);
        }
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/81628510
ZOJ