题意:有一个社交网络,每个玩家都有一个评分而且评分不同,一些玩家可以结交成朋友,朋友是相对而言的,意思就是说如果A是B的朋友,那么B也是A的朋友,每个玩家都有一个评分排名,他们知道自己的排名以及自己朋友的排名, Tom有n个朋友, 他在n个朋友中的排名是R,现在已知Tom朋友列表中有M对朋友,排名为Xi和排名为Yi的朋友互为朋友,还知道Tom列表中的排名为i的朋友,i在Ci个他的朋友的列表上评分占第一名,现在要求最少有多少个人是Tom的陌生人但是陌生人的朋友列表上评分排第一名的是Tom的朋友 来自题意
思路:超棒
每个朋友当第一的次数已经告诉你了是固定值,要求多少主人是陌生人,但排名第一是朋友的列表最少为多少。每个朋友当第一的次数有两部分组成,一部分是在陌生人列表里当第一,另一部分是在朋友列表里当第。一部分少,另一部分自然就多了,我们就可以求出每个朋友最多在朋友列表里当第一的次数。每个朋友当第一的次数 - 最多在朋友列表里当第一的次数 = 最少在陌生人列表里当第一的次数,然后累加求和就可以了。
f[i] 表示编号为i的朋友他的列表第一至少应该是编号为f[i]的人,这里,f[i]在i的朋友中优先选取Tom的朋友,因此两次用到f数组,第一次时i的朋友中有i和Tom,i和Tom嘛就选编号小的那个了。第二次是在输入朋友关系时,如果知道某个人是i的朋友,此时比较一下这个人的编号和f[i]那个小 f[x] = min(f[x],y);f[y] = min(f[y],x);。
num[i]就表示i最多在朋友列表里当第一的次数
#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define maxn 100010
using namespace std;
int ran[maxn],f[maxn],num[maxn];
int main()
{
int T;
scanf("%d",&T);
for(int k = 1;k <= T;k++)
{
int n,m,r;
LL ans = 0;
scanf("%d%d%d",&n,&m,&r);
memset(f,0,sizeof(f));
memset(num,0,sizeof(num));
for(int i = 1;i <= n;i++)
{
scanf("%d",&ran[i]);
f[i] = min(i,r);//有点意思
}
f[r] = 1;
for(int i = 1;i <= m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
f[x] = min(f[x],y);
f[y] = min(f[y],x);
}
for(int i = 1;i <= n;i++) num[f[i]]++;
for(int i = 1;i <= n;i++) ans = max(ans + ran[i] - num[i],0LL);
printf("Case #%d: %I64d\n",k,ans);
}
return 0;
}