题意:
在幼儿园里..每个小朋友投一票选举领导...得票最多的小朋友成为领导(若有多个..则多个领导)..现在有个小朋友相当唯一的领导..于是准备贿赂一些小朋友..让他们把票投给自己...每个小朋友要买通..必须满足给他的糖数...问这个小朋友最少用多少的糖使得他成为唯一的leader~
题解:
今天做的练习赛里的...比赛中各种没想法..想DP..但状态无法表示...想贪心..但一直没找到一个明确的方法...好乱...
这种模式的题目感觉没做过什么...由于数据范围不大...先枚举咱们这个小朋友是拿的多少个糖赢的..记为t...然后让其他的小朋友糖数小于t(大于t的.则减少到t-1)..而改变这些必然把选票加到自己头上来..寻则所需糖数最少的来操作...当所有小朋友的票数<t了..看咱这个1号小朋友..若他得到的票数大于了t..枚举失败..继续往更大的t进行枚举..若等于t..那么就已经得到了当前枚举条件下的最佳方案..若<t...则需要将还未买通的小朋友中糖数需求最小的几个给买通..让其票数正好等于t...
这道题还有个问题是1号小朋友要向别人投票...向票数最少的投就行了..又不可能所有的小朋友票数为t-1( t+(t-1)*(N-1)=N无整数解)...所以这个其实不用考虑..
Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<time.h>
#include<map>
#include<algorithm>
#define ll long long
#define eps 1e-5
#define oo 1<<30
#define pi acos(-1.0)
#define MAXN 105
using namespace std;
int f[MAXN],v[MAXN],sum[MAXN],id[MAXN];
bool used[MAXN];
bool cmp(int a,int b) { return v[a]<v[b]; }
int main()
{
int T,n,i,ans;
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
memset(sum,0,sizeof(sum));
for (i=2;i<=n;i++) scanf("%d",&f[i]),sum[f[i]]++;
for (i=2;i<=n;i++) scanf("%d",&v[i]);
ans=oo;
for (int t=max(sum[1],1);t<n;t++)
{
int data=0,x,num,h=sum[1];
memset(used,false,sizeof(used));
for (i=2;i<=n;i++)
if (sum[i]>=t)
{
h+=sum[i]-(t-1);
if (sum[1]>t) break;
num=0;
for (x=2;x<=n;x++)
if (f[x]==i) id[++num]=x;
sort(id+1,id+1+num,cmp);
for (x=1;x<=sum[i]-(t-1);x++) data+=v[id[x]],used[id[x]]=true;
}
if (sum[1]>t) continue;
num=0;
for (x=2;x<=n;x++)
if (!used[x]) id[++num]=x;
sort(id+1,id+1+num,cmp);
for (i=1;i<=t-h;i++) data+=v[id[i]];
ans=min(ans,data);
}
printf("%d\n",ans);
}
return 0;
}