天梯赛 GPLT L2-028 秀恩爱分得快(25 分)
L2-028 秀恩爱分得快(25 分)
古人云:秀恩爱,分得快。
互联网上每天都有大量人发布大量照片,我们通过分析这些照片,可以分析人与人之间的亲密度。如果一张照片上出现了 K 个人,这些人两两间的亲密度就被定义为 1/K。任意两个人如果同时出现在若干张照片里,他们之间的亲密度就是所有这些同框照片对应的亲密度之和。下面给定一批照片,请你分析一对给定的情侣,看看他们分别有没有亲密度更高的异性朋友?
输入格式:
输入在第一行给出 2 个正整数:N(不超过1000,为总人数——简单起见,我们把所有人从 0 到 N-1 编号。为了区分性别,我们用编号前的负号表示女性)和 M(不超过1000,为照片总数)。随后 M 行,每行给出一张照片的信息,格式如下:
K P[1] ... P[K]
其中 K(<= 500)是该照片中出现的人数,P[1] ~ P[K] 就是这些人的编号。最后一行给出一对异性情侣的编号 A 和 B。同行数字以空格分隔。题目保证每个人只有一个性别,并且不会在同一张照片里出现多次。
输出格式:
首先输出“A PA”,其中 PA 是与 A 最亲密的异性。如果 PA 不唯一,则按他们编号的绝对值递增输出;然后类似地输出“B PB”。但如果 A 和 B 正是彼此亲密度最高的一对,则只输出他们的编号,无论是否还有其他人并列。
输入样例 1:
10 4
4 -1 2 -3 4
4 2 -3 -5 -6
3 2 4 -5
3 -6 0 2
-3 2
输出样例 1:
-3 2
2 -5
2 -6
输入样例 2:
4 4
4 -1 2 -3 0
2 0 -3
2 2 -3
2 -1 2
-3 2
输出样例 2:
-3 2
题目说明:
我相信很多人都会想到 用一个1000x1000的浮点数组存储任意两个人之间的亲密度,但是如果每次读取一张照片时我们都将照片内的任意两人之间的亲密度更新一下,时间的的开销我们承受不起。对于题意的设定,我们考虑一下时间复杂度的极限,共1000张照片,每张照片500人,为了使程序达到运行时间极大值,我们假设每张照片中男女占半,隔位排列。这样对于一张照片,我们使用排列组合很容的的计算出这张数组的元素需要访问约500×500÷2=125000次,而亲密度数组的访问更新次数为约250×250÷2×2=62500次,再算上1千张照片需要访问,程序运行时间要想达到不超过500ms的要求,CPU和内存频率超爆了估计都够呛。
那么我们考虑另一种方式,我们预先存储所有照片的人员信息,对于某张照片来说,只有包含a元素时(500次访问),我们才再次遍历该照片以获得a和异性的亲密度(500次访问,250次更新),跟新至一个存储a和其他人员亲密度的桶数组中。对于需要考虑的b元素,同样的方式来一遍。那么对于这张照片,最多进行2000次访问,500次更新亲密度存储桶即可,总共1000张照片也不过200w次访问,50w次更新,这个时间开销我们是可以接受的。如果再简单优化一下,获得a和b是否存在的信息只需要一次遍历,同理获得亲密度时也只需要另一次遍历即可。
注意一下,-0代表人员0为女,当且仅当查询情侣双方均为对方最亲密的异性朋友时才只输出该对情侣。
下面给出程序的AC代码:
#include<bits/stdc++.h>
using namespace std;
bool gender[1000]={0}; //gender[person-id]=if-is-a-girl, 1 for girl, 0 for boy
int read(){
int input=0, flag=0;
char a=getchar();
while((a<'0' || a>'9') && a!='-')
a=getchar();
if(a=='-'){
flag=1;
a=getchar();
}
while(a>='0' && a<='9'){
input=input*10+a-'0';
a=getchar();
}
gender[input]=flag; //upgrade gender[] before exit
return input;
}
int main(){
int n, m, k, cnt, a, b;
double pa_max=0.0, pb_max=0.0;
scanf("%d%d",&n,&m);
vector<vector<int>> p(n); //photos
vector<double> pa(n,0.0), pb(n,0.0); //buckets, pa[person-id] = intimacy between a & person-id
for(unsigned int i=0;i<m;++i){ //read photos
scanf("%d",&cnt);
p[i].resize((unsigned int)cnt);
for(unsigned int j=0;j<cnt;++j)
p[i][j]=read();
}
a=read(), b=read();
for(unsigned int i=0;i<m;++i){
bool founda=find(p[i].begin(),p[i].end(),a)!=p[i].end(); //if this photo has a
bool foundb=find(p[i].begin(),p[i].end(),b)!=p[i].end(); //if this photo has b
if(founda || foundb){
for(unsigned int j=0;j<p[i].size();++j){
if(founda && gender[a]!=gender[p[i][j]]){ //if found a && current assessing person-id (p[i][j]) has a different gender from a's
pa[p[i][j]]+=(double)1/p[i].size();
pa_max=max(pa_max,pa[p[i][j]]);
}else if(foundb && gender[b]!=gender[p[i][j]]){ //else found b && current assessing person-id (p[i][j]) has a different gender from b's
pb[p[i][j]]+=(double)1/p[i].size();
pb_max=max(pb_max,pb[p[i][j]]);
}
}
}
}
if(pa_max==pa[b] && pb_max==pb[a]) //if a & b are each other's most intimate person
printf("%s%d %s%d\n",gender[a]?"-":"",a,gender[b]?"-":"",b);
else{
for(unsigned int i=0;i<n;++i){
if(pa[i]==pa_max)
printf("%s%d %s%d\n",gender[a]?"-":"",a,gender[i]?"-":"",i);
}
for(unsigned int i=0;i<n;++i){
if(pb[i]==pb_max)
printf("%s%d %s%d\n",gender[b]?"-":"",b,gender[i]?"-":"",i);
}
}
return 0;
}
运行时间:
参考: