PAT天梯赛L2-028 秀恩爱分得快 c语言 (“-0“)

古人云:秀恩爱,分得快。

互联网上每天都有大量人发布大量照片,我们通过分析这些照片,可以分析人与人之间的亲密度。如果一张照片上出现了 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

  
代码解释:使用的结构体数组进行存储,并且男女分开存的,在遍历时节省时间

第1点是要注意里面有-0 和0 的区别 所以只能用字符串输入,而且字符串的最少为5个空间,因为忽略了这一点,测试点4找了3个小时的错

第2点要注意会有双方亲密值都为0的测试点,这时相当于双方亲密值都是最高的,直接输出一行,但没有只有1方亲密值为0的测试点,代码中也没有考虑这一点

第3点 abs(0.009)==0 ,小数不能用abs,除法时要把总人数变为float型 

 代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
typedef struct node{
    int total;                //总人数
    int boy[500];             //记录照片上的男人
    int girl[500];           //记录照片上的女人
    int boynum;              //代表这张照片里男生人数
    int girlnum;             //代表女生人数
    int flag;                 //记录这张照片有没有男女主角
}ONE;
void FindPAPB(ONE photo[],int sexa,int sexb,int PA,int PB);
void updateFlag(int sex,ONE photo[],int i);
void FindGroupPhoto(int sex,ONE photo[],int *maxloc,float *Intimacy,float GroupPhoto[]);
void FindMaxLoc(int maxloc,float Intimacy,float GroupPhoto[],int loc[],int *top,int *flag,int P);

int n,m;                //n总人数 m照片数量
int main()
{
    scanf("%d%d",&n,&m);
    ONE photo[m];int temp;
    for (int i=0;i<m;i++) //初始化
    {
        photo[i].total=0;
        photo[i].girlnum=0;
        photo[i].boynum=0;
        photo[i].flag=0;
    }
    char str[10];
    for (int i=0;i<m;i++)
    {
        scanf("%d\n",&(photo[i].total));
        for (int j=0;j<photo[i].total;j++)
        {
            scanf("%s",str);        //!!!!!有-0 和 0 必须用字符串区分
            temp=atoi(str);
            if (!strcmp(str,"-0") || temp<0)
                photo[i].girl[photo[i].girlnum++]=temp;
            else
                photo[i].boy[photo[i].boynum++]=temp;
        }
    }
    //输入男女主角 并标志为男女
    char stra[5],strb[5];scanf("%s %s",stra,strb);//!!!!!!字符串长度最少为5 否则测试点4错误 
    int PA=atoi(stra),PB=atoi(strb),sexa=0,sexb=0; //-1代表女 1代表男
    if (!strcmp(stra,"-0") || PA<0)
        sexa--;
    else
        sexa++;
    if (!strcmp(strb,"-0") || PB<0)
       sexb--;
    else
        sexb++;
    
    FindPAPB(photo,sexa,sexb,PA,PB);            //找照片里是否有男女主角
    //GroupPhotoA GroupPhotoB数组下表代表合照的人的绝对值 里面的数代表亲密值
    float GroupPhotoA[1001]={0},GroupPhotoB[1001]={0}; 
    int maxlocA=0,maxlocB=0;                            //maxlocA为数组达到的最大下标 用于循环 节省时间
    float IntimacyA=0,IntimacyB=0;                        //IntimacyA记录最大亲密值
    FindGroupPhoto(sexa,photo,&maxlocA, &IntimacyA, GroupPhotoA );
    FindGroupPhoto(sexb,photo,&maxlocB, &IntimacyB, GroupPhotoB );
   //flag是0代表双方亲密值都没有最大 1代表某一个人亲密值最大 2代表双方亲密值都最大
    int flag=0;                                      
    int locA[maxlocA],locB[maxlocB],topA=0,topB=0;    //找照片里面达到最大亲密值的并记录在locA、locB数组里面 记录着最大的位置
    FindMaxLoc(maxlocA,IntimacyA,GroupPhotoA,locA,&topA,&flag,PB);
    FindMaxLoc(maxlocB,IntimacyB,GroupPhotoB,locB,&topB,&flag,PA);
    
    //输出 !!!!!! 测试点里面没有只有其中1方最大亲密值为0的 只有测试点3两方亲密值都为0
    if (flag==2 || (!IntimacyA && !IntimacyB))    //如果 A 和 B 正是彼此亲密度最高的一对 或者 !!!!!1张照片也没有(测试点3) 只输出这一对
        printf("%s %s\n",stra,strb);
    else                                    //如果AB不是彼此亲密值最大的一对 则输出亲密值最大的所有人
    {
        for (int i=0;i<topA;i++)
        {
            if (sexa<0 )
                printf("%s %d\n",stra,locA[i]);//直接由stra输出 不用再分-0的情况
            else
                printf("%s -%d\n",stra,locA[i]);
        }
        for (int i=0;i<topB;i++)
        {
            if (sexb<0  )
                printf("%s %d\n",strb,locB[i]);
            else 
                printf("%s -%d\n",strb,locB[i]);
        }
    }
}

/*!!!!!输入  测试点3类似
10 0
-0 1
输出
-0 1*/
 //找照片里有没有男女主角
void FindPAPB(ONE photo[],int sexa,int sexb,int PA,int PB) 
{
    for (int i=0;i<m;i++)                 //标志如果只有该女的标志为-1 只有该男的标志为1 都有标志为2
    {
        for (int j=0;j<photo[i].girlnum;j++)
        {
            if (sexa<0 && PA==photo[i].girl[j] )  //a是女的并且照片里有
                updateFlag(sexa,photo,i);    
            else if(sexb<0 && PB==photo[i].girl[j])    //b是女的并且照片里有
                updateFlag(sexb,photo,i);
        }
        for (int j=0;j<photo[i].boynum;j++)
        {
             if(sexa>0 && PA==photo[i].boy[j])
                updateFlag(sexa,photo,i);
             else if(sexb>0 && PB==photo[i].boy[j])
               updateFlag(sexb,photo,i);
        }
    }
}
//更新结构体里的flag 如果为1代表有男主角 -1代表女主角 2代表都有
void updateFlag(int sex,ONE photo[],int i)
{
    if(photo[i].flag)            //如果已经有其中一个了
    {
        photo[i].flag=2;
        return;
    }
    if (sex<0)
        photo[i].flag=-1;
    else
        photo[i].flag=1;
}
//找合照的人
void FindGroupPhoto(int sex,ONE photo[],int *maxloc,float *Intimacy,float GroupPhoto[])
{
    for (int i=0;i<m;i++)                    
    {
        if (sex>0)                        //如果是男的 找女的
        {
            if (!(photo[i].flag==1 || photo[i].flag==2))//如果这张照片没有这男的
                continue;
            for (int j=0;j<photo[i].girlnum;j++)
            {
                GroupPhoto[abs(photo[i].girl[j])]+=(1/(float)photo[i].total);//必须有float
                if (abs(photo[i].girl[j]) > *maxloc)        //maxloc记录GroupPhoto的最大下标 访问时节省时间
                    *maxloc = abs(photo[i].girl[j]);
                if (GroupPhoto[abs(photo[i].girl[j])] > *Intimacy)        //Intimacy记录最大亲密值
                    *Intimacy = GroupPhoto[abs(photo[i].girl[j])];      //不能加abs abs(0.009)=0  //printf("\n%f",abs(0.09));
            }
        }
        else            //如果是女的
        {
             if(!(photo[i].flag==-1 || photo[i].flag==2))//  只有1或0时才中断  或者if (photo[i].flag!=-1 && photo[i].flag!=2)也对
                continue;
            for (int j=0;j<photo[i].boynum;j++)
            {
                GroupPhoto[photo[i].boy[j]]+=(1/(float)photo[i].total);
                if (abs(photo[i].boy[j]) > *maxloc)
                    *maxloc = abs(photo[i].boy[j]);
                if (GroupPhoto[photo[i].boy[j]] > *Intimacy)
                    *Intimacy = GroupPhoto[photo[i].boy[j]];
            }
        }
    }
}//找照片里面达到最大亲密值的并记录在locA、locB数组里面 记录着最大的位置
void FindMaxLoc(int maxloc,float Intimacy,float GroupPhoto[],int loc[],int *top,int *flag,int P)
{
    for (int i=0;i<=maxloc && Intimacy;i++)  //亲密值不能为0 因为GroupPhoto数组的初值全为0
    {
        if (GroupPhoto[i]==Intimacy)
        {
            loc[(*top)++]=i;    //必须加()
            if (i==P || i==-P)
                (*flag)++;
        }
    }
}



### 关于 PAT 天梯赛 L2-001 紧急救援 的分析 题目描述通常涉及在一个加权图中找到从起点到终点的最短路径,同时满足某些条件(如最大权重边最小)。此类问题可以通过 **Dijkstra算法** 和 **优先队列优化** 来解决。 #### 图论基础回顾 在图论中,单源最短路径问题是经典的算法问题之一。对于带正权值的有向无环图 (Directed Acyclic Graph, DAG),或者一般的加权图,Dijkstra 是一种高效的解决方案[^1]。该算法通过维护一个优先队列来动态更新节点的距离,并逐步扩展已知最优路径至目标节点。 针对本题的具体需求——不仅需要求出最短路径长度,还需要记录路径上的最大权重以及可能的不同路径数量,以下是详细的解答思路: --- #### 数据结构设计 为了高效处理输入数据并支持后续查询操作,需定义如下辅助类或变量: 1. 使用邻接表存储图的信息。 2. 定义三个数组分别保存当前顶点的状态: - `dist[v]` 表示从起始点到达 v 的最短距离; - `max_edge[v]` 记录从起点到 v 路径上遇到的最大边权值; - `path_count[v]` 统计有多少条不同的路径能够达到相同的 `(dist[v], max_edge[v])` 值组合。 初始化时设所有顶点不可达 (`inf`) 并设置起点状态为零。 --- #### 主要逻辑流程 采用 Dijkstra 算法的核心思想,结合优先队列实现多维度比较功能。具体步骤如下所示: 1. 初始化优先队列 PQ,按照三元组 `(distance, maximum edge weight, node)` 排序,其中 distance 应作为主要关键字升序排列,maximum edge weight 则次之降序排列。 2. 将初始结点加入队列,其对应的距离和最大边权均置为 0;路径数记作 1。 3. 循环提取队首元素 u 进行松弛操作:遍历与 u 相连的所有邻居 w,尝试更新它们的相关属性。如果发现更优解,则同步调整 dist[w], max_edge[w] 及 path_count[w] 的取值;当新旧两方案具有相同效果时累加路径数目即可。 4. 结束循环直至访问完全图中的每一个可触及位置为止。 最终输出结果应包括总耗时、途中经历过的最高危险等级数值以及符合条件的有效路线总数模去某个固定常量后的余数形式呈现出来。 --- #### 实现代码样例 下面是基于 Python 编写的完整程序版本: ```python import heapq def dijkstra(n, start, end, graph): INF = float('inf') # Initialize arrays to store distances, max edges and counts. dist = [INF]*n max_edge = [-1]*n count = [0]*n pq = [(0, 0, start)] # Priority queue with tuple of (current_distance, current_max_edge, vertex). dist[start] = 0 max_edge[start] = 0 count[start] = 1 while pq: d_u, m_e_u, u = heapq.heappop(pq) if u == end: break for v, cost in graph[u]: alt_dist = d_u + cost # Compute the new potential 'max edge' value along this route. candidate_me_v = max(m_e_u, cost) if alt_dist < dist[v]: dist[v] = alt_dist max_edge[v] = candidate_me_v count[v] = count[u] # Push updated state into priority queue. heapq.heappush(pq, (alt_dist, candidate_me_v, v)) elif alt_dist == dist[v] and candidate_me_v < max_edge[v]: max_edge[v] = candidate_me_v count[v] += count[u] return dist[end], max_edge[end], count[end]%int(1e9+7) if __name__ == "__main__": n_vertices, n_edges, src, dst = map(int, input().split()) g = [[]for _ in range(n_vertices)] for i in range(n_edges): a,b,cost=map(int,input().strip().split()) g[a].append((b,cost)) res=dijkstra(n_vertices,src,dst,g) print(*res) ``` 上述脚本实现了完整的读入解析过程并通过标准输入获取必要的参数配置信息之后调用了核心函数完成任务执行最后按指定格式打印答案内容. --- #### 时间复杂度分析 由于采用了二叉堆作为底层支撑的数据结构,在每次迭代过程中最多只需要 O(log E) 的时间成本来进行插入/删除动作,因此整体运行效率大致维持在线性对数级别范围内即 O(E log V)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值