题意:n人合伙买一件价格为p的礼物,每个人有自己能承担的最大费用,要保证尽可能公平,使付钱多的人和付钱少的人钱数的差距尽可能小,如果存在矛盾,先来的人比后来的付钱多。
分析:要使尽可能公平,可以先将总价格平分,如果有人能承担的最大费用比平均价格要少,则要支付自己全部的钱,然后剩余的钱由其它人循环按照此法解决,当最终剩余的人能承担的最大费用都比当前平均费用多时,则按照题目规则需多付钱的人比其他人少付1cent即可完全解决问题。可见该题是一道贪心问题,可创建结点数组a用于保存每人能承担的最大费用s和自己的序号x,用数组b按序号保存没人需要支付的费用。下面附上AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=10005;
int p,n;
bool vis[maxn]; //标记数组,若某结点已访问,则将其按序号标记为true
struct node
{
int s,x;
}a[maxn];
int b[maxn];
bool cmp(const node &a,const node &b) //将结点数组按s从小到大排序,若s相同则按x从小到大排序
{
if(a.s<b.s) return true;
else if(a.s==b.s) return a.x>b.x;
return false;
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(vis,false,sizeof vis);
scanf("%d%d",&p,&n);
ll sum=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i].s);
a[i].x=i;
sum+=a[i].s;
}
if(sum<p)
{
puts("IMPOSSIBLE");
continue;
}
int nn=n;
while(p)
{
sort(a,a+n,cmp);
int ave=p/nn,mod=p%nn;
int num=0;
for(int i=0;i<n;i++)
{
if(vis[a[i].x]) continue;
if(a[i].s<=ave)
{
b[a[i].x]=a[i].s;
p-=a[i].s;
vis[a[i].x]=true;
num++;
nn--;
}
else break;
}
if(num==0)
{
for(int i=n-1;i>=0;i--)
{
if(vis[a[i].x]) continue;
if(mod)
{
b[a[i].x]=ave+1;
mod--;
}
else b[a[i].x]=ave;
}
break;
}
}
for(int i=0;i<n-1;i++)
printf("%d ",b[i]);
printf("%d\n",b[n-1]);
}
return 0;
}