题目
目标
了解图的遍历和递归算法的应用。通过构建人际关系图,然后使用深度优先搜索(DFS)进行遍历,判断陌生人之间是否满足握手条件,从而计算握手次数。
题目描述
算上扶苏,本次派对共有 n 个人。但是,并不是任何两个人都互相认识,并且互相认识的人关系也未必好。 具体而言,任意两个人可能是如下三种关系之一:
1.敌人
2.朋友
3.陌生人
派对的一大重要活动是相互握手。对任意两个人 么,u,他们之间的握手情况遵循下面的规则:
1.如果 u和 u 是朋友关系,那么他们一定握手一次。
2.如果 u和 u 是敌人关系,那么他们一定不握手。
3.如果u和u 是陌生人关系,且存在一个人 w,使得w是u和u之一的朋友,同时是 u,u 中另一人的敌人,则 u和u 不会握手,否则 u和 u 一定握手一次。
对第三条规则,简单的说法是:一对陌生人之间,如果某一方的朋友是另一方的敌人,则不握手,否则握手。
已知共有 p 对人是朋友关系,g 对人是敌人关系。除了这p+ g 对人,其他每对人均为陌生人关系请你求出本次派对一共握手了多少次。
输入格式:
第一行是三个整数,依次表示参加派对的人数 n,朋友关系的条数 p 和敌人关系的条数 q。
接下来 p 行,每行两个整数 u,u,表示u和 u 是朋友关系。
接下来 q 行,每行两个整数 u,u,表示 u和 u 是敌人关系。
输出格式:
输出一行一个整数,表示本次派对的握手次数,
输入/输出示例
输入示例:
4 2 2
1 2
2 3
1 4
1 3
输出示例:
3
解题方法
思路说明
解题思路如下:
-
首先,我们需要建立一个图来表示人与人之间的关系。每个人可以表示为图中的一个节点,而朋友关系和敌人关系可以表示为图中的边。
-
我们使用两个哈希映射来存储朋友关系和敌人关系。其中,朋友关系的映射中,键表示一个人,值表示他的朋友;敌人关系的映射中,键表示一个人,值表示他的敌人。
-
接下来,我们根据朋友关系的映射构建图的邻接表表示。遍历朋友关系的映射,对于每对朋友关系 (u, v),我们将 u 和 v 加入彼此的邻接表中。
-
然后,我们使用深度优先搜索(DFS)来遍历图。从每个未访问过的节点开始,进行DFS遍历。在DFS过程中,我们检查陌生人之间的握手条件:如果某一方的朋友是另一方的敌人,则不握手,否则握手一次。
-
在DFS过程中,每次满足握手条件时,将握手次数加1,并继续对下一个节点进行DFS遍历。
-
最后,得到的握手次数即为本次派对的握手次数。
通过以上步骤,我们找到所有满足握手条件的节点对,并计算握手次数。
代码实现
package com.lgf.demo;
import java.util.Scanner;
public class PartyHandshakes {
public static void main(String[] args) {
long count = 0;
int people, Friend, enemy;
Scanner scanner = new Scanner(System.in);
people = scanner.nextInt();
Friend = scanner.nextInt();
enemy = scanner.nextInt();
int[][] relation = new int[people][people];
// 初始化关系矩阵
for (int i = 0; i < people; i++) {
for (int j = 0; j < people; j++) {
relation[i][j] = 0;
}
relation[i][i] = -1;
}
// 读取朋友关系
for (int f = 0, row, column; f < Friend; f++) {
row = scanner.nextInt();
column = scanner.nextInt();
relation[row - 1][column - 1] = relation[column - 1][row - 1] = 1;
}
// 读取敌人关系
for (int e = 0, row, column; e < enemy; e++) {
row = scanner.nextInt();
column = scanner.nextInt();
relation[row - 1][column - 1] = relation[column - 1][row - 1] = 2;
}
// 遍历所有人,计算握手次数
for (int p = 0; p < people - 1; p++) {
for (int it = p + 1; it < people; it++) {
if (relation[p][it] == 0) {
// 如果是陌生人关系,则判断是否满足握手条件
if (isStrangerHandshakePossible(relation, p, it)) {
count++;
}
} else if (relation[p][it] == 1) {
// 如果是朋友关系,则一定握手
count++;
}
}
}
System.out.println(count);
}
// 判断两个陌生人之间是否满足握手条件
private static boolean isStrangerHandshakePossible(int[][] relation, int person1, int person2) {
boolean handshakePossible = true;
for (int i = 0; i < relation.length; i++) {
if (i != person1 && i != person2) {
if (relation[person1][i] == 1 && relation[person2][i] == 2) {
// 如果其中一个人的朋友是另一个人的敌人,则不满足握手条件
return false;
}
}
if (relation[person1][i] == 0 && i != person2) {
// 如果是陌生人关系,则尝试进行握手并递归判断后续握手情况
relation[person1][i] = relation[i][person1] = 1;
handshakePossible = handshakePossible && isStrangerHandshakePossible(relation, i, person2);
relation[person1][i] = relation[i][person1] = 0;
}
}
return handshakePossible;
}
}