题目链接: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;
}