题目大意就是给你一些人以及他们的社交参数,每两个人交流一次,他们的社交参数就会各自减一,当社交参数减少为0时,这个人将无法交流,问社交参数减少的权值和最多为多少。
分析:我一开始想的是对这些人的社交能力进行从大到小排序,然后依次选择社交参数最大和次大的人进行交流,当社交参数次大的人社交参数为0时,再把社交参数最大的那个人的剩余社交参数加回队列,依次重复上述过程,我这样想是有问题的,比如
有三个人 社交参数分别为 2 2 2,按照我的那种思路,算出来的结果是2,但正确结果应该是1号先与2号交流,再分别用1号和2号与三号交流,这样得到的结果是3。
这个样例就启发我们对原来的想法加以完善,就是每次选取社交参数最大和次大的人进行交流,但是每次只交流一次,使他们的社交参数分别减1,再次将他们加入队列,重新选取社交参数最大和次大的人进行交流,重复上述过程,直至队列中只剩下一个人。下面是代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int N=2e5+10;
int l[N],r[N];
struct node{
int pos,val;
bool operator<(const node &t)const{
return t.val>val;
}
};
priority_queue<node>q;
int main()
{
int T;
cin>>T;
while(T--)
{
while(q.size()) q.pop();
int n;
scanf("%d",&n);
int t;
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
if(t)//如果值不为0就加入队列
q.push({i,t});
}
int cnt=0;//记录交谈次数
long long ans=0;
while(q.size()>=2)
{
node a=q.top();
q.pop();
node b=q.top();
q.pop();
l[++cnt]=a.pos;
r[cnt]=b.pos;
if(a.val>1)
q.push({a.pos,a.val-1});
if(b.val>1)
q.push({b.pos,b.val-1});
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++)
printf("%d %d\n",l[i],r[i]);
}
return 0;
}