L2-4 秀恩爱分得快 (25 point(s))
古人云:秀恩爱,分得快。
互联网上每天都有大量人发布大量照片,我们通过分析这些照片,可以分析人与人之间的亲密度。如果一张照片上出现了 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
-
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define maxn 4019
int n,m,k[maxn],A,B,sexa,sexb;
int fu[maxn],pic[maxn][maxn],pwa[maxn],pwb[maxn];
double pa[maxn],pb[maxn];
vector<int>ans1,ans2;
struct gg
{
int id;//人的编号
double v;//与A或B的亲密程度
} p1[maxn],p2[maxn];
int read(char*str,int ans,int *fu_)
{
if(str[0]=='-')
{
int len=strlen(str);
rep(t,1,len)
ans=ans*10+str[t]-'0';
*fu_=-1;
}
else
{
int len=strlen(str);
rep(t,0,len)
ans=ans*10+str[t]-'0';
*fu_=0;
}
return ans;
}
void getpwith_(int index,int row)
{
memset(pwa,0,sizeof(pwa));
int sex=index==1?sexa:sexb;
rep(j,0,k[row])
{
int peo=pic[row][j];
if(fu[peo]!=sex)
{
if(index)
pwa[peo]=1;
else
pwb[peo]=1;
}
}
}
int cmp(gg x,gg y)
{
if(x.v!=y.v)
return x.v>y.v;
return x.id<y.id;
}
int main()
{
//字符串输入:考虑输入-0的情况
//字符串输出:考虑输入含-0的情况
scanf("%d%d",&n,&m);
rep(i,0,m)
{
scanf("%d",&k[i]);
char str[maxn];//局部使用
//(1)读取pic[][]:存储出现过的每张图片里的具体人物编号和性别
rep(j,0,k[i])
{
scanf("%s",str);
//读取多位数
int fu_;
pic[i][j]=read(str,pic[i][j],&fu_);
fu[pic[i][j]]=fu_;
}
}
char AA[maxn],BB[maxn];
scanf("%s%s",AA,BB);
A=read(AA,0,&sexa);
B=read(BB,0,&sexb);
/******特判,当某个人和谁的好感度都是0,这时候只输出所有异性**************************/
rep(i,0,n){
if(fu[i]==sexa)
pa[i]+=-1;
if(fu[i]==sexb)
pb[i]+=-1;
}
/***********************************************/
//(2)计算flaga,flagb(局部变量):标记计算m张图片里是否出现过A,B
rep(i,0,m)
{
int flaga=0;
int flagb=0;
rep(j,0,k[i])
{
if(pic[i][j]==A)
flaga=1;
if(pic[i][j]==B)
flagb=1;
}
if(flaga) //计算A在局部和每个人同框的次数
{
getpwith_(1,i);
rep(j,0,k[i])
pa[pic[i][j]]+=pwa[pic[i][j]]/double(k[i]);
}
if(flagb)//计算B在局部和每个人同框的次数
{
getpwith_(0,i);
rep(j,0,k[i])
pb[pic[i][j]]+=pwb[pic[i][j]]/double(k[i]);
}
}
rep(i,0,n)
p1[i].id=i,p1[i].v=pa[i],p2[i].id=i,p2[i].v=pb[i];
sort(p1,p1+n,cmp);
sort(p2,p2+n,cmp);
double maxa=p1[0].v;
rep(i,0,n)
{
if(p1[i].v!=maxa)
break;
else
ans1.push_back(p1[i].id);
}
double maxb=p2[0].v;
rep(i,0,n)
{
if(p2[i].v!=maxb)
break;
else
ans2.push_back(p2[i].id);
}
/*********************输出****************************/
int len1=ans1.size();
int f1=0;
rep(i,0,len1)
{
if(pa[ans1[i]]==pa[B])
f1=1;
}
int len2=ans2.size();
int f2=0;
rep(i,0,len2)
{
if(pb[ans2[i]]==pb[A])
f2=1;
}
if(f1&&f2)
{
if(sexa==-1)
cout<<'-'<<A<<" ";
else
cout<<A<<" ";
if(sexb==-1)
cout<<'-'<<B<<endl;
else
cout<<B<<endl;
}
else
{
rep(i,0,len1)
{
if(sexa==-1)
cout<<'-'<<A<<" ";
else
cout<<A<<" ";
if(fu[ans1[i]]==-1)
cout<<'-'<<ans1[i]<<endl;
else
cout<<ans1[i]<<endl;
}
rep(i,0,len2)
{
if(sexb==-1)
cout<<'-'<<B<<" ";
else
cout<<B<<" ";
if(fu[ans2[i]]==-1)
cout<<'-'<<ans2[i]<<endl;
else
cout<<ans2[i]<<endl;
}
}
return 0;
}
-
思路:
- 将每个人的性别存如数组,如0号对应性别是男,则fu[0]=1,否则fu[0]=0;
- 用两个数组分别表示每个人与A,B的好感度:pa[某人]=某人与A的好感度;pb[某人]=某人与B的好感度。
- 遍历n个人,如果这个人和A是同性(包括A和A自身),pa[某人]=-1;pb同理
- 遍历m张照片,判断每张照片中是否出现过A,如果出现过,将这张照片中所有的异性用一个数组元素标记为1,最后将被标记过的异性对应的临时数组元素的值++;出现过B同理。
- 遍历所有人,pa[某人]+=临时数组每个元素值处以K[i],i代表照片i。pb同理
- 根据pa,pb对所有人进行排序。得到和A关系度最高的人的id,B同理
- 输出
-
需要特判的数据:
1) Input: 8 3 5 -7 0 -5 3 2 3 4 1 6 0 4 -5 Output: 4 -5 4 -7 -5 0 -5 2 -5 3 2) 出现某人编号为-0 输出的时候也得是-0 (不详细给出数据)