【题解】【PAT甲】 1139 First Contact (30 分)(测试点1,2,3,4,5)

27 篇文章 0 订阅

题目链接

 PTA | 程序设计类实验辅助教学平台

题目描述

Unlike in nowadays, the way that boys and girls expressing their feelings of love was quite subtle in the early years. When a boy A had a crush on a girl B, he would usually not contact her directly in the first place. Instead, he might ask another boy C, one of his close friends, to ask another girl D, who was a friend of both B and C, to send a message to B -- quite a long shot, isn't it? Girls would do analogously.

Here given a network of friendship relations, you are supposed to help a boy or a girl to list all their friends who can possibly help them making the first contact.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers N (1 < N ≤ 300) and M, being the total number of people and the number of friendship relations, respectively. Then M lines follow, each gives a pair of friends. Here a person is represented by a 4-digit ID. To tell their genders, we use a negative sign to represent girls.

After the relations, a positive integer K (≤ 100) is given, which is the number of queries. Then K lines of queries follow, each gives a pair of lovers, separated by a space. It is assumed that the first one is having a crush on the second one.

Output Specification:

For each query, first print in a line the number of different pairs of friends they can find to help them, then in each line print the IDs of a pair of friends.

If the lovers A and B are of opposite genders, you must first print the friend of A who is of the same gender of A, then the friend of B, who is of the same gender of B. If they are of the same gender, then both friends must be in the same gender as theirs. It is guaranteed that each person has only one gender.

The friends must be printed in non-decreasing order of the first IDs, and for the same first ones, in increasing order of the seconds ones.

Sample Input:

10 18
-2001 1001
-2002 -2001
1004 1001
-2004 -2001
-2003 1005
1005 -2001
1001 -2003
1002 1001
1002 -2004
-2004 1001
1003 -2002
-2003 1003
1004 -2002
-2001 -2003
1001 1003
1003 -2001
1002 -2001
-2002 -2003
5
1001 -2001
-2003 1001
1005 -2001
-2002 -2004
1111 -2003

结尾无空行

Sample Output:

4
1002 2004
1003 2002
1003 2003
1004 2002
4
2001 1002
2001 1003
2002 1003
2002 1004
0
1
2003 2001
0

结尾无空行

题目大意

 A对B有好感,先找一个和自己同性的朋友C,然后C找一个和B同性的朋友D,然后D再找B

A B同性也是这个方法,同性不能A->C->B这种找法,也应该是A->C->D->B这种找法

其中正数代表男性,负数代表女性

输出格式

在一种情况内,先输出A的好友,再输出B的好友

在不同情况内,按照A朋友id从小到大排序,如果相等,在按照B好友从小到大的顺序

解题思路

测试点1是因为输出不是四位格式所以导致错误,%04d

测试点2是因为没有考虑-0000是女性的情况

测试点3、4、5三个点都存在ABCD重合的情况,比如C==B,D==A,C==D的情况

还需要注意的点是当AB为不同性别时,由C找D的时候需要额外排除B

当AB为同性的时候,由A找C,由C找D都需要避开B

一开始是考虑采用dfs,因为可能有多种情况,有多种情况的话需要对情况进行排序,所以一开始没有考虑二维int数组而是用string来存储每种情况,方便对最后结果进行排序,结果导致最后一个测试点超时,只能得26分

#include<bits/stdc++.h>
using namespace std;
struct Node{
	int gender=1;
	int id;
};
unordered_map<int,vector<Node>> ma;
vector<string> path;
vector<int> tempPath;
int visited[10005];
int st,en;
int g,g2;
void dfs(int id,int num){
	if(id==abs(en)){
		string t;
		string s;
		for(int i=0;i<tempPath.size();i++){
			if(i!=0)	t+=" ";
			s=to_string(tempPath[i]);
			s.insert(0,4-s.length(),'0');
			t+=s;
		}
		path.push_back(t);
		return ;
	}
	for(int i=0;i<ma[id].size();i++){
		if(visited[ma[id][i].id]==0){
			if(num==0){        //只能找和st同性的,而且不能是en
				if(ma[id][i].gender==g&&ma[id][i].id!=abs(en)){
					visited[ma[id][i].id]=1;
					tempPath.push_back(ma[id][i].id);
					dfs(ma[id][i].id,num+1);
					tempPath.pop_back();
					visited[ma[id][i].id]=0;
				}
			}
			else if(num==1){    //只能找和en同性的,不能是en
				if(ma[id][i].gender==g2&&ma[id][i].id!=abs(en)){
					visited[ma[id][i].id]=1;
					tempPath.push_back(ma[id][i].id);
					dfs(ma[id][i].id,num+1);
					tempPath.pop_back();
					visited[ma[id][i].id]=0;
				}
			}
			else{            //只能找en
				if(ma[id][i].id==abs(en)){
					visited[ma[id][i].id]=1;
					dfs(ma[id][i].id,num+1);
					visited[ma[id][i].id]=0;
				}
			}
		}
	}
}
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++){
		string a,b;
		Node ta,tb;
		cin>>a>>b;
		if(a[0]=='-')	ta.gender=0;
		ta.id=abs(stoi(a));
		if(b[0]=='-')	tb.gender=0;
		tb.id=abs(stoi(b));
		ma[ta.id].push_back(tb);
		ma[tb.id].push_back(ta);
	}
	int k;
	cin>>k;
	while(k--){
		tempPath.clear();
		path.clear();
		scanf("%d %d",&st,&en);
		if(st<0)	g=0;
		else	g=1;
		if(en<0)	g2=0;
		else	g2=1;
		visited[abs(st)]=1;
		dfs(abs(st),0);
		visited[abs(st)]=0;
		sort(path.begin(),path.end());
		printf("%d\n",path.size());
		for(int i=0;i<path.size();i++){
			cout<<path[i]<<endl;
		}
	}
} 

发现其实只要遍历A的所有朋友和B的所有朋友,当满足条件的时候判断C和D是不是有联系就可以了

二重循环避免超时 

题解

#include<bits/stdc++.h>
using namespace std;
struct Node{
	int gender=1;
	int id;
};
struct Node2{
	int a,b;
};
unordered_map<int,vector<Node>> ma;
vector<Node2> path;
int visited[10005];
int st,en;
int g,g2;
bool cmp(Node2 a,Node2 b){
	return a.a==b.a?a.b<b.b:a.a<b.a;
} 
map<pair<int,int>,int> touch;
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++){
		string a,b;
		Node ta,tb;
		cin>>a>>b;
		if(a[0]=='-')	ta.gender=0;
		ta.id=abs(stoi(a));
		if(b[0]=='-')	tb.gender=0;
		tb.id=abs(stoi(b));
		ma[ta.id].push_back(tb);
		ma[tb.id].push_back(ta);
		touch[make_pair(ta.id,tb.id)]=1;
		touch[make_pair(tb.id,ta.id)]=1;
	}
	int k;
	cin>>k;
	while(k--){
		path.clear();
		scanf("%d %d",&st,&en);
		if(st<0)	g=0;
		else	g=1;
		if(en<0)	g2=0;
		else	g2=1;
		for(int i=0;i<ma[abs(st)].size();i++){
			for(int j=0;j<ma[abs(en)].size();j++){
				if(ma[abs(st)][i].gender==g&& 		//C和A性别相同 
				ma[abs(st)][i].id!=abs(en)&&		//C不能等于B 
				ma[abs(en)][j].id!=abs(st)&&		//D不能等于A 
				ma[abs(en)][j].id!=ma[abs(st)][i].id&&	//C不能等于D 
				ma[abs(en)][j].gender==g2&&			//D和B的性别相等 
				touch[make_pair(ma[abs(st)][i].id,ma[abs(en)][j].id)]==1){
				//C和D有联系	
					path.push_back(Node2{ma[abs(st)][i].id,ma[abs(en)][j].id});
				}
			}
		}
		sort(path.begin(),path.end(),cmp);
		printf("%d\n",path.size());
		for(int i=0;i<path.size();i++){
			printf("%04d %04d\n",path[i].a,path[i].b);
		}
	}
} 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值