[GPLT] 2022 大众情人(floyd)

赛时大概有一个小时写这个大众情人,被网卡爆了(,刚写完的代码准备提交,网络超时。。。oms直接卡退。。再次滚进去后重新敲了一遍准备交又卡没了。。今天找到可以交题的地方就调了下bug,ac了(在评测系统里打代码还是得慎重,以后还是在本地编译器写,)

题目描述:

输入:

输出&样例:

题目有点又臭又长,大致解释下题意

有N个人,分男女,a->b(a对b有关系,距离感为num1),b->c(b对c有关系,距离感为num2)则可以有a->c(a对c有关系,距离感为num1+num2)。因为一个人的异性缘与对自己最无感的人决定的,所以A的异性缘可以转化为A所有的异性中对A距离感最大的值(最无感)。大众情人即为在同性人中与异性距离最大值最小的(可以有多个) 输出女性中的大众情人和男性中的大众情人。

将N个人之间的关系连成有向图(注意不是无向图,a->b与b->a的距离感可以不等)。因为对每个人都要求所有异性对他/她的最短距离(关系可以传递),故而,可以转化为多源最短路径问题。

N<=500,数据范围不是很大,可以直接考虑简单粗暴的Floyd(核心算法只有五行呢!)。1.求出任意两者之间的最短路. 2.再对每个人求他/她的异性缘(距离最大的那个决定)为了方便,我直接用了两个结构体数组来分别记录女性和男性的异性与自己距离的最大值. 3.分别从小到大排序一下,与异性距离最大值最小的便是大众情人,直接输出即可。

具体详见代码:

#include <bits/stdc++.h>
using namespace std;
struct node
{
    char sex;                //性别
    int idx, num;            //分别对应下标和最大距离(异性缘由对他/她最无感的那个异性决定的)
} a[510], b[510], c[510];    // a存入初始每个人的输入数据,b存女性数据,c存男性
int e[510][510], cnt1, cnt2; // cnt1记录女性人数,cnt2记录男性人数
bool cmp(node x, node y)
{
    if (x.num == y.num)
        return x.idx < y.idx;
    return x.num < y.num;
}
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) // floyd初始化(初始时二者没有关系,设为inf)
        for (int j = 1; j <= n; j++)
            if (i != j)
                e[i][j] = 1e9;
            else
                e[i][j] = 0;
    for (int i = 1; i <= n; i++)
    {
        getchar(); //吸收上一个换行符
        int m;
        scanf("%c%d", &a[i].sex, &m);
        a[i].idx = i; //存入下标
        for (int j = 1; j <= m; j++)
        {
            int x, y;
            scanf("%d:%d", &x, &y);
            e[i][x] = y; // i->x的距离为y
        }
    }
    for (int k = 1; k <= n; k++)                 //枚举中转点
        for (int i = 1; i <= n; i++)             //枚举起点
            for (int j = 1; j <= n; j++)         //枚举终点
                if (e[i][j] > e[i][k] + e[k][j]) //可以通过k更新i,j的距离则更新i,j的最短路
                    e[i][j] = e[i][k] + e[k][j];
    for (int i = 1; i <= n; i++) //对每个人求其异性缘
    {
        int res = 0; //当前的异性缘,要找到距离最大的故初始为最小值,这里设置为0
        int j;
        for (j = 1; j <= n; j++)
        {
            if (a[i].sex != a[j].sex)    // j与i为异性->更新异性缘
                res = max(res, e[j][i]); //注意!是j->i而不是i->j,因为是异性对自己的距离
        }
        if (a[i].sex == 'F') // i为女性,将她的下标,异性缘值存入b
        {
            b[++cnt1].num = res;
            b[cnt1].idx = a[i].idx;
        }
        else // i为男性,将他的下标,异性缘值存入c
        {
            c[++cnt2].num = res;
            c[cnt2].idx = a[i].idx;
        }
    }
    sort(b + 1, b + 1 + cnt1, cmp); //排序找与异性距离最大值最小的
    sort(c + 1, c + 1 + cnt2, cmp);
    int i = 1, ok = 0;
    while (b[i].num == b[1].num && i <= cnt1) //输出女性中所有并列的
    {
        if (ok)
            cout << " "; //输出格式处理,行末不能有多余的空格
        cout << b[i].idx;
        i++;
        ok = 1;
    }
    i = 1;
    ok = 0;
    cout << endl;
    while (c[i].num == c[1].num && i <= cnt2) //输出男性中所有并列的
    {
        if (ok)
            cout << " ";
        cout << c[i].idx;
        i++;
        ok = 1;
    }
}

代码可能有点冗长,但思路还是比较简单的

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

self_disc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值