题意:有n个选民和依次标号的m个政党,每个选民可投一票,也可以花钱收买这个选民让他投你指定的任党派。给你这n个选民原本支持的党派和收买他们的花费,问如何花最少的钱让1号党派胜出(所获选票比其余任意一个党派都多,相等也不可以哦)
没什么思路,怎么想都感觉处理各种情况很复杂。研究了别人的代码,发现用的是枚举+贪心。即,从i=1~n枚举1号党在得到i票的情况下胜出的花费,那么此时别的党最多只能让他获得i-1票,当有一个关键选民要投给别的党第i票是就收买他(提前按每个人的c从大到小排序,让收买这个关键选民的钱尽量小)并让贿赂标记 vis[j]=1 。之后如果1党还是没有得到i票,就贿赂那些没有收买过的选民,每次都贿赂花费最小的那个。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct Vote
{
int p;
int c;
}voter[3009];
bool cmp(Vote a,Vote b)
{
return a.c>b.c;
}
int vote[3009];
int vis[3009];
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>voter[i].p>>voter[i].c;
long long ans=1e16;
sort(voter,voter+n,cmp);
for(int i=1;i<=n;i++)
{
memset(vote,0,sizeof(vote));
memset(vis,0,sizeof(vis));
long long sum=0ll;
for(int j=0;j<n;j++)
{
if(voter[j].p==1) vote[1]++;
else if(vote[voter[j].p]+1==i){
vis[j]=1;//收买过的人打标记
vote[1]++;
sum+=voter[j].c;
}
else vote[voter[j].p]++;
}
for(int j=n-1;j>=0;j--) {
if(vote[1]<i&&!vis[j]&&voter[j].p!=1){//voter[j].p!=1一定要加
sum+=voter[j].c;
vote[1]++;
vote[j]--;
}
}
ans=min(ans,sum);
}
cout<<ans<<endl;
return 0;
}