PAT | A1139 First Contact(待优化)

一开始的思路:
从源点开始进行深度不超过3的DFS,深度到达3时判断是否到达终点,到达则记录当前路径。
想得太复杂了,且最后有三个点答案错误,也没有考虑正负零的差别。
一开始的代码:

#include <iostream>
#include <unordered_set>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

struct Friend{
	int first;
	int second;
};

vector<int> G[10000];
unordered_set<int> students;
vector<Friend> res;
stack<int> st;

bool cmp(Friend a,Friend b){
	if(a.first != b.first)
		return abs(a.first) < abs(b.first);
	return abs(a.second) < abs(b.second);
}

void DFS(int source,int s,int d,int level){
	if(level == 1){ // 要找一个和s一样性别的
		if(s < 0){
			for(int i = 0;i < G[abs(s)].size();i++){
				if(G[abs(s)][i] < 0 && G[abs(s)][i] != source && G[abs(s)][i] != d){
					st.push(G[abs(s)][i]);
					DFS(source,G[abs(s)][i],d,2);
					st.pop();
				}
			}
		}else{
			for(int i = 0;i < G[s].size();i++){
				if(G[s][i] > 0 && G[s][i] != source && G[s][i] != d){
					st.push(G[s][i]);
					DFS(source,G[s][i],d,2);
					st.pop();
				}
			}
		}
	}else if(level == 2){ // 要找一个和d一样性别的
		if(d < 0){
			for(int i = 0;i < G[abs(s)].size();i++){
				if(G[abs(s)][i] < 0 && G[abs(s)][i] != source && G[abs(s)][i] != d){
					st.push(G[abs(s)][i]);
					DFS(source,G[abs(s)][i],d,3);
					st.pop();
				}
			}
		}else{
			for(int i = 0;i < G[abs(s)].size();i++){
				if(G[abs(s)][i] > 0 && G[abs(s)][i] != source && G[abs(s)][i] != d){
					st.push(G[abs(s)][i]);
					DFS(source,G[abs(s)][i],d,3);
					st.pop();
				}
			}
		}
	}else{ // 要找d
		for(int i = 0;i < G[abs(s)].size();i++){
			if(G[abs(s)][i] == d){ // 找到
				Friend temp;
				temp.second = st.top();
				st.pop();
				temp.first = st.top();
				st.push(temp.second);
				res.push_back(temp);
				break;
			}
		}
	}
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 0;i < m;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		students.insert(u);
		students.insert(v);
		G[abs(u)].push_back(v);
		G[abs(v)].push_back(u);
	}
	int k;
	scanf("%d",&k);
	for(int i = 0;i < k;i++){
		int source,destination;
		scanf("%d%d",&source,&destination);
		res.clear();
		DFS(source,source,destination,1);
		sort(res.begin(),res.end(),cmp);
		printf("%d\n",res.size());
		for(int j = 0;j < res.size();j++){
			printf("%d %d\n",abs(res[j].first),abs(res[j].second));
		}
	}
	system("pause");
	return 0;
}

看了网上其他大神的做法后,决定用一个数组存放某个同学的同性朋友。
对每个A的同性朋友B和D的同性朋友C,判断B和C是否是朋友,是则记录,注意在朋友中去掉A的同性朋友是D和D的同性朋友是A的情况即可。
但依旧有测试点答案错误,暂时还没想到错在哪。待优化

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <algorithm>

using namespace std;

struct Friend{
	int first;
	int second;
	Friend(int f,int s){
		first = f;
		second = s;
	}
	Friend(){}
};

namespace std{
    template <>
    struct hash<Friend>{
        size_t operator()(Friend const & x) const{
			return(51 + std::hash<int>()(x.first) * 51 + std::hash<int>()(x.second));
        }
    };
}

bool operator==(const struct Friend & X,const struct Friend & Y){
	return (hash<int>()(X.first) == hash<int>()(Y.first) && hash<int>()(X.second) == hash<int>()(Y.second));
}

//bool G[10000][10000]; // 两个人是否是朋友
unordered_set<Friend> G;
unordered_map<int,bool> gender;
vector<int> sameGenderFriends[10000]; // 同性朋友
vector<Friend> res;

bool cmp(Friend a,Friend b){
	return (a.first == b.first) ? (a.second < b.second) : (a.first < b.first);
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 0;i < m;i++){
		string a,b;
		int u,v;
		cin>>a>>b;
		stringstream sa,sb;
		sa<<a;
		sa>>u;
		sb<<b;
		sb>>v;
		u = abs(u);
		v = abs(v);
		if(a[0] == '-')
			gender[u] = false;
		else
			gender[u] = true;
		if(b[0] == '-')
			gender[v] = false;
		else
			gender[v] = true;
		G.insert(Friend(u,v));
		if(gender[u] == gender[v]){ // 两人同性
			sameGenderFriends[u].push_back(v);
			sameGenderFriends[v].push_back(u);
		}
	}
	int k;
	scanf("%d",&k);
	for(int i = 0;i < k;i++){
		res.clear();
		int source,destination;
		scanf("%d%d",&source,&destination);
		source = abs(source);
		destination = abs(destination);
		for(int j = 0;j < sameGenderFriends[source].size();j++){ // 对源点的每一个同性朋友:
			if(sameGenderFriends[source][j] == destination)
				continue;
			for(int p = 0;p < sameGenderFriends[destination].size();p++){ // 对终点的每一个同性朋友:
				if(sameGenderFriends[destination][p] == source)
					continue;
				if(G.find(Friend(sameGenderFriends[source][j],sameGenderFriends[destination][p])) != G.end()
					||
					G.find(Friend(sameGenderFriends[destination][p],sameGenderFriends[source][j])) != G.end()){
					res.push_back(Friend(sameGenderFriends[source][j],sameGenderFriends[destination][p]));
				}
			}
		}
		sort(res.begin(),res.end(),cmp);
		printf("%d\n",res.size());
		for(int j = 0;j < res.size();j++){
			printf("%d %d\n",res[j].first,res[j].second);
		}
	}
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值