P14361 [CSP-S 2025] 社团招新 / club 题解
这是一道很考验细心的贪心题,挺有意思的。
思路比较简单:
- 每个人选满意度最高的部门是最优解,满意度最高的部门成为这个人的 首选部门
- 如果一个部门的首选人数超过\(\frac{n}{2}\) ,那么其他部门不再有首选人数超过\(\frac{n}{2}\)的可能性
- 当出现超过限制的情况时,为了让更多人选到首选部门,有些人需要换到次要部门(满意度排第二的部门),更换的过程会带来满意度的损失,所以我们选择损失最小的,降序即可。
考虑到每个人的满意度有三种,使用结构体维护,这样方便进行排序和处理。
我用a,b,c代表三个部门,fst代表首选部门,sec代表次要部门,pri代表损失(首选部门换成次要部门带来的损失),vis代表是否被访问。
flag代表是否超出限制,tmp统计每次处理的人数。
一边调一边想,写了好久,虽然很长,但是看起来比较清晰。
比我这个代码简单和快捷的题解应该很多吧。
#include<bits/stdc++.h>
using namespace std;
#define long long ll
int t,n;
struct pp{
int a,b,c,fst,sec,pri;
int vis=0;
}P[100010];
bool cmp1(pp x,pp y)
{
return x.a>y.a;
}
bool cmp2(pp x,pp y)
{
return x.b>y.b;
}
bool cmp3(pp x,pp y)
{
return x.c>y.c;
}
bool cmp4(pp x,pp y)
{
return x.pri<y.pri;
}
int tmp,tot,flag,cha;
int main()
{
cin>>t;
while(t--)
{
tot=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>P[i].a>>P[i].b>>P[i].c;
if(P[i].a>=P[i].b&&P[i].b>=P[i].c)
{
P[i].fst=1,P[i].sec=2,P[i].pri=P[i].a-P[i].b;
}else if(P[i].a>=P[i].c&&P[i].c>=P[i].b)
{
//a>c>b
P[i].fst=1,P[i].sec=3,P[i].pri=P[i].a-P[i].c;
}else if(P[i].b>=P[i].a&&P[i].a>=P[i].c)
{
//b>a>c
P[i].fst=2,P[i].sec=1,P[i].pri=P[i].b-P[i].a;
}else if(P[i].b>=P[i].c&&P[i].c>=P[i].a)
{
//b>c>a
P[i].fst=2,P[i].sec=3,P[i].pri=P[i].b-P[i].c;
}else if(P[i].c>=P[i].a&&P[i].a>=P[i].b)
{
//c>a>b
P[i].fst=3,P[i].sec=1,P[i].pri=P[i].c-P[i].a;
}else{
//c>b>a
P[i].fst=3,P[i].sec=2,P[i].pri=P[i].c-P[i].b;
}
}
//第一部分
tmp=0;
sort(P+1,P+n+1,cmp1);
flag=0;
for(int i=1;i<=n;i++)
{
if(P[i].fst==1&&P[i].vis==0)
{
// tot+=P[i].a;
// P[i].vis=1;
tmp++;
}
if(tmp>n/2)
{
flag=1;
// break;
}
}
// cout<<tmp<<endl;
cha=tmp-n/2;
tmp=0;
if(!flag)
{
for(int i=1;i<=n;i++)
{
if(P[i].fst==1&&P[i].vis==0)
{
tot+=P[i].a;
P[i].vis=1;
tmp++;
}
if(tmp>=n/2)
{
break;
}
}
}else{
sort(P+1,P+n+1,cmp4);
tmp=0;
for(int i=1;i<=n;i++)
{
if(!P[i].vis&&P[i].fst==1)
{
tmp++;
if(P[i].sec==1)
{
tot+=P[i].a;
}else if(P[i].sec==2)
{
tot+=P[i].b;
}else{
tot+=P[i].c;
}
P[i].vis=1;
}
if(tmp>=cha) break;
}
sort(P+1,P+n+1,cmp1);
tmp=0;
for(int i=1;i<=n;i++)
{
if(P[i].fst==1&&P[i].vis==0)
{
tot+=P[i].a;
P[i].vis=1;
tmp++;
}
if(tmp>=n/2) break;
}
}
//第二部分
flag=0;
tmp=0;
sort(P+1,P+1+n,cmp2);
for(int i=1;i<=n;i++)
{
if(P[i].fst==2&&P[i].vis==0)
{
tmp++;
}
if(tmp>n/2)
{
flag=1;
}
}
cha=tmp-n/2;
tmp=0;
if(!flag)
{
//cout<<"in2"<<endl;
for(int i=1;i<=n;i++)
{
if(P[i].fst==2&&P[i].vis==0)
{
tot+=P[i].b;
P[i].vis=1;
tmp++;
}
if(tmp>=n/2)
{
break;
}
}
}else{
sort(P+1,P+n+1,cmp4);
tmp=0;
for(int i=1;i<=n;i++)
{
if(!P[i].vis&&P[i].fst==2)
{
tmp++;
if(P[i].sec==1)
{
tot+=P[i].a;
}else if(P[i].sec==2)
{
tot+=P[i].b;
}else{
tot+=P[i].c;
}
P[i].vis=1;
}
if(tmp>=cha) break;
}
sort(P+1,P+n+1,cmp2);
tmp=0;
for(int i=1;i<=n;i++)
{
if(P[i].fst==2&&P[i].vis==0)
{
tot+=P[i].b;
P[i].vis=1;
tmp++;
}
if(tmp>=n/2) break;
}
}
//第三部分
flag=0;
tmp=0;
sort(P+1,P+1+n,cmp3);
for(int i=1;i<=n;i++)
{
if(P[i].fst==3&&P[i].vis==0)
{
// tot+=P[i].a;
// P[i].vis=1;
tmp++;
}
if(tmp>n/2)
{
flag=1;
// break;
}
}
cha=tmp-n/2;
tmp=0;
if(!flag)
{
//cout<<"in3"<<endl;
for(int i=1;i<=n;i++)
{
if(P[i].fst==3&&P[i].vis==0)
{
tot+=P[i].c;
P[i].vis=1;
tmp++;
}
if(tmp>=n/2)
{
break;
}
}
}else{
sort(P+1,P+n+1,cmp4);
tmp=0;
for(int i=1;i<=n;i++)
{
if(!P[i].vis&&P[i].fst==3)
{
tmp++;
if(P[i].sec==1)
{
tot+=P[i].a;
}else if(P[i].sec==2)
{
tot+=P[i].b;
}else{
tot+=P[i].c;
}
P[i].vis=1;
}
if(tmp>=cha) break;
}
sort(P+1,P+n+1,cmp3);
tmp=0;
for(int i=1;i<=n;i++)
{
if(P[i].fst==3&&P[i].vis==0)
{
tot+=P[i].c;
P[i].vis=1;
tmp++;
}
if(tmp>=n/2) break;
}
}
cout<<tot<<endl;
for(int i=1;i<=n;i++)
{
P[i].vis=0;
}
// tot=0,tmp=0,flag=0;
}
return 0;
}

浙公网安备 33010602011771号