天梯赛L2-044 大众情人(Floyd最短路)

今天看到PTA更新了天梯赛的题目,果断去做了一下当时没写完的题(ps:我是fw,今年的题目也太恶心了叭)

原题链接:传送门

思路

根据题面,要先跑一遍Floyd最短路,注意是有向图,之后按照题意排个序就好啦

题目描述

人与人之间总有一点距离感。我们假定两个人之间的亲密程度跟他们之间的距离感成反比,并且距离感是单向的。例如小蓝对小红患了单相思,从小蓝的眼中看去,他和小红之间的距离为 1,只差一层窗户纸;但在小红的眼里,她和小蓝之间的距离为 108000,差了十万八千里…… 另外,我们进一步假定,距离感在认识的人之间是可传递的。例如小绿觉得自己跟小蓝之间的距离为 2,则即使小绿并不直接认识小红,我们也默认小绿早晚会认识小红,并且因为跟小蓝很亲近的关系,小绿会觉得自己跟小红之间的距离为 1+2=3。当然这带来一个问题,如果小绿本来也认识小红,或者他通过其他人也能认识小红,但通过不同渠道推导出来的距离感不一样,该怎么算呢?我们在这里做个简单定义,就将小绿对小红的距离感定义为所有推导出来的距离感的最小值。

一个人的异性缘不是由最喜欢他/她的那个异性决定的,而是由对他/她最无感的那个异性决定的。我们记一个人 i 在一个异性 j 眼中的距离感为Dij;将 i 的“异性缘”定义为 1/max j∈S(i){Dij},其中 S(i) 是相对于 i 的所有异性的集合。那么“大众情人”就是异性缘最好(值最大)的那个人。

本题就请你从给定的一批人与人之间的距离感中分别找出两个性别中的“大众情人”。

输入格式

输入在第一行中给出一个正整数 N(≤500),为总人数。于是我们默认所有人从 1 到 N 编号。

随后 N 行,第 i 行描述了编号为 i 的人与其他人的关系,格式为:

性别 K 朋友1:距离1 朋友2:距离2 …… 朋友K:距离K

其中 性别 是这个人的性别,F 表示女性,M 表示男性;K(<N 的非负整数)为这个人直接认识的朋友数;随后给出的是这 K 个朋友的编号、以及这个人对该朋友的距离感。距离感是不超过1e6的正整数。

题目保证给出的关系中一定两种性别的人都有,不会出现重复给出的关系,并且每个人的朋友中都不包含自己。

输出描述

第一行给出自身为女性的“大众情人”的编号,第二行给出自身为男性的“大众情人”的编号。如果存在并列,则按编号递增的顺序输出所有。数字间以一个空格分隔,行首尾不得有多余空格。

输入样例

6
F 1 4:1
F 2 1:3 4:10
F 2 4:2 2:2
M 2 5:1 3:2
M 2 2:2 6:2
M 2 3:1 2:5

输出描述

2 3
4

代码

#include<bits/stdc++.h>

using namespace std;

typedef pair<int, double>PII; //first存编号,second存该编号的异性缘 
int n;
int mp[510][510];
unordered_map<int, int>xb; //xb为1是男性,为2是女性 
vector<PII>man,woman; //分别存男生和女生的异性缘 

bool cmp(PII x, PII y)
{
	if(x.second == y.second) return x.first < y.first; //如果异性缘一样,按编号递增排序 
	return x.second > y.second; //按异性缘降序排序 
}

int main()
{
    memset(mp, 0x3f, sizeof mp); //设初始距离为无穷 
    cin >> n;
    for(int i = 1; i <= n; i ++ )
    {
    	int k;
    	char c;
    	cin >> c >> k;
		for(int j = 1; j <= k; j ++ )
		{
			int x,y;
			scanf("%d:%d", &x, &y);
			mp[i][x] = y; //有向图 
		}
		if(c == 'M') xb[i] = 1;
		else xb[i] = 2;
	}
	 
    for(int i = 1; i <= n; i ++ ) mp[i][i] = 0;
    for(int k = 1; k <= n; k ++ )
    {
        for(int i = 1; i <= n; i ++ )
        {
            for(int j = 1; j <= n; j ++ )
            {
                mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
            }
        }
    }
    //以上为Floyd最短路的模板
	 
    for(int i = 1; i <= n; i ++ ) //i = 1开始遍历,遍历每个异性和i的距离 
    {
    	int maxx = -1;
    	for(int j = 1; j <= n; j ++ )
    	{
    		if(i != j && xb[i] != xb[j]) //如果是异性就取距离最大值 
    		{
    			maxx = max(maxx, mp[j][i]);
			}
		}
		if(xb[i] == 1) man.push_back({i, 1.0 / maxx});
		else woman.push_back({i, 1.0 / maxx});
	}
	sort(man.begin(), man.end(), cmp);
	sort(woman.begin(), woman.end(), cmp);
	//按题目要求输出即可 
	cout << woman[0].first;
	for(int i = 1; i < woman.size(); i ++ )
	{
		if(woman[i].second == woman[i - 1].second) cout << " " << woman[i].first;
		else break;
	}
	cout << '\n';
	cout << man[0].first;
	for(int i = 1; i < man.size(); i ++ )
	{
		if(man[i].second == man[i - 1].second) cout << " " << man[i].first;
		else break;
	}
    return 0;
}
<think>好的,我需要解决用户关于L2-044大众情人”问题的Python代码请求。首先,我需要回忆这道题的具体要求。根据引用[2]和[3],题目涉及人与人之间的距离计算,并需要确定大众情人。题目中的关键点包括: 1. 初始化两两之间的距离为无穷大,建立单向边。 2. 使用Floyd算法计算所有点对之间的短距离,因为n=500,Floyd的时间复杂度是O(),这在Python中可能有点挑战,但应该可行。 3. 将男性和女性分开存储,然后根据计算结果找出每个人的“异性距离”中的大值,再在异性中找出小值作为候选,后确定大众情人。 接下来,我需要考虑如何实现这些步骤。首先,处理输入。每个人的性别和其与其他人的关系需要正确读取。例如,输入格式可能是每个人一行,包含性别和多个k: d的键值对,表示他们到k号人的距离是d。这里需要注意,题目中的边是单向的,即i到k的距离是d,但k到i的距离可能不同,除非另有说明。 然后,初始化一个500x500的距离矩阵,初始值为无穷大。Python中可以用一个二维列表,初始值设为float('inf'),然后对角线设为0,因为自己到自己的距离是0。 接下来,应用Floyd-Warshall算法来更新所有点对之间的短路径。三重循环,k在外层,i和j在内层。需要注意的是,由于Python的性能问题,对于n=500,三重循环可能会有较高的时间消耗,但根据题目描述,引用[2]提到直接跑Floyd就能过,所以应该可以接受。 处理完短路径后,需要分别处理男性和女性的情况。对于每个女性,需要找出所有男性对她的距离中的大值,然后在所有女性中找出这些大值的小值,这样的女性就是女性中的大众情人。同理,男性也是类似的处理方式,但性别相反。 具体来说,对于每个候选人,需要遍历所有异性,找到他们到该候选人的距离,取大值(即该候选人在异性中的远距离),然后在所有同性别的候选人中找出这些大值的小值。后,所有达到该小值的候选人即为大众情人。 现在,我需要将这些步骤转化为代码。可能的代码结构如下: 1. 读取n,初始化距离矩阵。 2. 读取每个人的信息,更新距离矩阵。 3. 运行Floyd算法。 4. 分离男女。 5. 对每个性别,计算每个人的异性大距离。 6. 找到每个性别中的小值,然后收集所有达到该值的候选人。 7. 输出结果。 需要注意的细节包括输入处理中的索引是否正确(比如是否从1开始还是0开始),以及如何处理无穷大的情况。例如,在计算异性距离时,如果某异性到当前人的距离是无穷大,说明他们之间没有路径,这可能不符合题目条件,但题目可能有隐藏条件需要处理,比如确保所有可能的路径存在。但根据引用[3],用户提到初始化无穷大才能通过,所以必须正确设置初始值。 另外,输出时需要按照编号升序排列,所以后的结果列表需要排序。 可能的错误点包括Floyd的三重循环顺序是否正确,是否正确处理了单向边,以及男女的分类是否正确。例如,性别用字符'M'和'F'表示,需要正确分类。 现在,结合这些思考,编写代码的步骤大致如下: - 输入n,建立距离矩阵,初始为inf,对角线为0。 - 对于每个人i,读取性别和后面的k: d对,更新dist[i][k-1] = d(假设输入中的k是1-based,而代码中使用0-based索引)。 - 运行Floyd算法,更新所有短路径。 - 分离男女到两个列表。 - 对于女性大众情人:遍历每个女性,找到所有男性到她的距离的大值,然后找到所有女性中的小值,并收集对应的女性。 - 同样处理男性大众情人- 输出结果,排序后的编号(可能需要+1转回1-based)。 现在,测试代码是否覆盖了可能的边界情况,例如当某个异性无法到达时如何处理。但根据题目描述,可能所有测试用例都保证存在解,即每个异性对候选人都有可达的路径,或者题目中的输入保证不会有这种情况。需要确保代码在遇到无穷大时不会出错,但根据引用[3],用户提到正确初始化无穷大才能通过,因此可能测试数据中存在需要处理的情况,比如不相连的情况需要排除,或者题目中的输入数据保证所有必要的路径存在。 后,编写代码时需要注意Python中的列表索引是否正确,避免off-by-one错误。例如,如果题目中的输入编号是1-based,而代码中使用0-based,那么在处理k时需要减1。</think>以下是L2-044 大众情人问题的Python实现代码,基于Floyd算法实现: ```python def main(): import sys input = sys.stdin.read().split('\n') idx = 0 n = int(input[idx]) idx += 1 INF = float('inf') dist = [[INF] * n for _ in range(n)] for i in range(n): dist[i][i] = 0 male = [] female = [] for i in range(n): parts = input[idx].split() idx += 1 gender = parts[0] if gender == 'F': female.append(i) else: male.append(i) for item in parts[2:]: k, d = item.split(':') k = int(k) - 1 # 转换为0-based索引 dist[i][k] = int(d) # Floyd算法 for k in range(n): for i in range(n): for j in range(n): if dist[i][j] > dist[i][k] + dist[k][j]: dist[i][j] = dist[i][k] + dist[k][j] # 处理女性大众情人 min_f = INF result_f = [] for f in female: max_dist = 0 for m in male: d = dist[m][f] # 男性到女性的距离 if d > max_dist: max_dist = d if max_dist < min_f: min_f = max_dist result_f = [f + 1] # 转回1-based elif max_dist == min_f: result_f.append(f + 1) # 处理男性大众情人 min_m = INF result_m = [] for m in male: max_dist = 0 for f in female: d = dist[f][m] # 女性到男性的距离 if d > max_dist: max_dist = d if max_dist < min_m: min_m = max_dist result_m = [m + 1] elif max_dist == min_m: result_m.append(m + 1) # 输出结果 print(' '.join(map(str, sorted(result_f)))) print(' '.join(map(str, sorted(result_m)))) if __name__ == "__main__": main() ``` ### 关键点说明 1. **输入处理**:读取数据时将1-based编号转换为0-based存储,注意处理性别标识和关系数据[^2] 2. **Floyd算法**:使用三重循环更新所有点对的短距离,时间复杂度$O(n^3)$适用于n=500的情况[^3] 3. **距离计算**:对每个候选人计算异性群体中的大距离时,注意方向性(男性到女性/女性到男性) 4. **结果筛选**:先找出每个性别的候选人的大异性距离,再筛选小值对应的候选人 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值