题目链接:点击打开链接
思路:分析可知,有以下几个问题要处理,一是如何存储整个关系网;二是如何快速判断两个人之间是否存在朋友关系;三是如何将每个询问相应的结果存储并排序。题目没什么难度,采取合适的数据结构去处理以上三个问题即可,就是有一些坑点要注意。
七种方法(优化或不同方法):
一:前向星存图;利用set
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct node{
int v;
int next;
}edge[200000];//开小了出现段错误
int cnt,head[10000];
int sex[10000];
void Add(int u,int v){
cnt++;
edge[cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt;
return;
}
void Nint(){
cnt = 0;
memset(head,0,sizeof(head));
memset(sex,-1,sizeof(sex));
return;
}
int Change(char s[]){
int num = 0;
if(s[0] == '-'){
for(int i = 1;i <= 4;i++){
num = num*10 + s[i] - '0';
}
sex[num] = 0;
return num;
}
else{
for(int i = 0;i < 4;i++){
num = num*10 + s[i] - '0';
}
sex[num] = 1;
return num;
}
}
struct cmp{
bool operator()(const pair &a,const pair &b)const{
if(a.first != b.first){
return a.first < b.first;
}
else{
return a.second < b.second;
}
}
};
set > s;
set,cmp> re;
int main(){
int n,m,k;
char a[10],b[10];
scanf("%d%d",&n,&m);
Nint();
for(int i = 0;i < m;i++){
scanf("%s%s",a,b);//这样读取的原因是有易错点:-0000
int aa = Change(a);
int bb = Change(b);
Add(aa,bb);
Add(bb,aa);
s.insert(pair(aa,bb));//使用make_pair会在PAT上编译错误
s.insert(pair(bb,aa));
}
scanf("%d",&k);
while(k--){
re.clear();
scanf("%s%s",a,b);
int aa = Change(a);
int bb = Change(b);
for(int i = head[aa];i;i = edge[i].next){
int c = edge[i].v;
if(bb == c || sex[aa] != sex[c]) continue;//易错点,别忘记判断找到的B不是D
for(int j = head[bb];j;j = edge[j].next){
int d = edge[j].v;
if(aa == d || sex[bb] != sex[d]) continue;//易错点,别忘记判断找到的C不是A
if(s.find(pair(c,d)) != s.end()){
re.insert(pair(c,d));
}
}
}
printf("%d\n",re.size());
for(set,cmp>::iterator it = re.begin();it != re.end();it++){
printf("%04d %04d\n",it->first,it->second);//%04d为易错点
}
}
return 0;
}
/*
pair a(1,2);
pair c;
c = make_pair(2,3);//utility头文件中
*/
二:vector存图;利用set
优化:vector只存储和自己性别相同的朋友关系
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector v[10000];
int sex[10000];
int Change(char s[]){
int num = 0;
if(s[0] == '-'){
for(int i = 1;i <= 4;i++){
num = num*10 + s[i] - '0';
}
sex[num] = 0;
return num;
}
else{
for(int i = 0;i < 4;i++){
num = num*10 + s[i] - '0';
}
sex[num] = 1;
return num;
}
}
struct cmp{
bool operator()(const pair &a,const pair &b)const{
if(a.first != b.first){
return a.first < b.first;
}
else{
return a.second < b.second;
}
}
};
set > s;
set,cmp> re;
int main(){
int n,m,k;
char a[10],b[10];
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
scanf("%s%s",a,b);//这样读取的原因是有易错点:-0000
int aa = Change(a);
int bb = Change(b);
if(sex[aa] == sex[bb]){//只存和自己性别相同的朋友
v[aa].push_back(bb);
v[bb].push_back(aa);
}
s.insert(pair(aa,bb));//使用make_pair会在PAT上编译错误
s.insert(pair(bb,aa));
}
scanf("%d",&k);
while(k--){
re.clear();
scanf("%s%s",a,b);
int aa = Change(a);
int bb = Change(b);
for(int i = 0;i < v[aa].size();i++){
int c = v[aa][i];
if(bb == c || sex[aa] != sex[c]) continue;//易错点,别忘记判断找到的B不能是D
for(int j = 0;j < v[bb].size();j++){
int d = v[bb][j];
if(aa == d || sex[bb] != sex[d]) continue;//易错点,别忘记判断找到的C不能是A
if(s.find(pair(c,d)) != s.end()){
re.insert(pair(c,d));
}
}
}
printf("%d\n",re.size());
for(set,cmp>::iterator it = re.begin();it != re.end();it++){
printf("%04d %04d\n",it->first,it->second);//%04d为易错点
}
}
return 0;
}
三:vector存图;利用set
优化:读取ID时,直接用string读取,利用string的length就可判断出性别是否一样,然后vector也只是存储性别相同的朋友关系。把string转化为无符号整数直接利用stoi(c++中)和abs(C语言中)函数即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector v[10000];
struct cmp{
bool operator()(const pair &a,const pair &b)const{
if(a.first != b.first){
return a.first < b.first;
}
else{
return a.second < b.second;
}
}
};
set > s;
set,cmp> re;
int main(){
int n,m,k;
string a,b;
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
cin >> a >> b;//这样读取的原因是有易错点:-0000
int aa = abs(stoi(a));//stoi是C++的string中的函数;与atoi不同,atoi是C语言中的
int bb = abs(stoi(b));//abs也和fabs一样,是C语言math.h中的函数
if(a.length() == b.length()){
v[aa].push_back(bb);
v[bb].push_back(aa);
}
s.insert(pair(aa,bb));//使用make_pair会在PAT上编译错误
s.insert(pair(bb,aa));
}
scanf("%d",&k);
while(k--){
re.clear();
int aa,bb;
scanf("%d%d",&aa,&bb);
aa = abs(aa);
bb = abs(bb);
for(int i = 0;i < v[aa].size();i++){
int c = v[aa][i];
if(bb == c) continue;//易错点,别忘记判断找到的B不能是D
for(int j = 0;j < v[bb].size();j++){
int d = v[bb][j];
if(aa == d) continue;//易错点,别忘记判断找到的C不能是A
if(s.find(pair(c,d)) != s.end()){
re.insert(pair(c,d));
}
}
}
printf("%d\n",re.size());
for(set,cmp>::iterator it = re.begin();it != re.end();it++){
printf("%04d %04d\n",it->first,it->second);//%04d为易错点
}
}
return 0;
}
四:vector存图;利用set
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector v[10000];
set > s;
struct node{
int aa,bb;
node(int c,int d):aa(c),bb(d){}
bool operator<(const node &c)const{
if(this->aa != c.aa){
return this->aa < c.aa;
}
else{
return this->bb < c.bb;
}
}
};
vector re;
int main(){
int n,m,k;
string a,b;
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
cin >> a >> b;//这样读取的原因是有易错点:-0000
int aa = abs(stoi(a));//stoi是C++的string中的函数;与atoi不同,atoi是C语言中的
int bb = abs(stoi(b));//abs也和fabs一样,是C语言math.h中的函数
if(a.length() == b.length()){
v[aa].push_back(bb);
v[bb].push_back(aa);
}
s.insert(pair(aa,bb));//使用make_pair会在PAT上编译错误
s.insert(pair(bb,aa));
}
scanf("%d",&k);
while(k--){
re.clear();
int aa,bb;
scanf("%d%d",&aa,&bb);
aa = abs(aa);
bb = abs(bb);
for(int i = 0;i < v[aa].size();i++){
int c = v[aa][i];
if(bb == c) continue;//易错点,别忘记判断找到的B不能是D
for(int j = 0;j < v[bb].size();j++){
int d = v[bb][j];
if(aa == d) continue;//易错点,别忘记判断找到的C不能是A
if(s.find(pair(c,d)) != s.end()){
re.push_back(node(c,d));
}
}
}
sort(re.begin(),re.end());
printf("%d\n",re.size());
for(int i = 0;i < re.size();i++){
printf("%04d %04d\n",re[i].aa,re[i].bb);//%04d为易错点
}
}
return 0;
}
五:vector存图;利用set
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector v[10000];
bool cmp(pair a,pair b){
if(a.first != b.first){
return a.first < b.first;
}
else{
return a.second < b.second;
}
}
set > s;
vector > re;
int main(){
int n,m,k;
string a,b;
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
cin >> a >> b;//这样读取的原因是有易错点:-0000
int aa = abs(stoi(a));//stoi是C++的string中的函数;与atoi不同,atoi是C语言中的
int bb = abs(stoi(b));//abs也和fabs一样,是C语言math.h中的函数
if(a.length() == b.length()){
v[aa].push_back(bb);
v[bb].push_back(aa);
}
s.insert(pair(aa,bb));//使用make_pair会在PAT上编译错误
s.insert(pair(bb,aa));
}
scanf("%d",&k);
while(k--){
re.clear();
int aa,bb;
scanf("%d%d",&aa,&bb);
aa = abs(aa);
bb = abs(bb);
for(int i = 0;i < v[aa].size();i++){
int c = v[aa][i];
if(bb == c) continue;//易错点,别忘记判断找到的B不能是D
for(int j = 0;j < v[bb].size();j++){
int d = v[bb][j];
if(aa == d) continue;//易错点,别忘记判断找到的C不能是A
if(s.find(pair(c,d)) != s.end()){
re.push_back(pair(c,d));
}
}
}
sort(re.begin(),re.end(),cmp);
printf("%d\n",re.size());
for(int i = 0;i < re.size();i++){
printf("%04d %04d\n",re[i].first,re[i].second);//%04d为易错点
}
}
return 0;
}
六:vector存图;利用二维数组快速判断朋友关系;vector
优化;直接利用二维数组标记朋友关系,方便。之前感觉就算开为bool,65536kB的内存还是不够bool[10^4][10^4],但试了一下可以,应该和系统内存分配有关,但要注意的一点是,当使用memset,会超出内存限制。即使这样,超过内存限制或者超过语言限制的过大数组最好不要使用!!!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector v[10000];
bool map[10000][10000];
bool cmp(pair a,pair b){
if(a.first != b.first){
return a.first < b.first;
}
else{
return a.second < b.second;
}
}
vector > re;
int main(){
int n,m,k;
string a,b;
scanf("%d%d",&n,&m);
//memset(map,false,sizeof(map));加了这个超出内存限制
for(int i = 0;i < m;i++){
cin >> a >> b;//这样读取的原因是有易错点:-0000
int aa = abs(stoi(a));//stoi是C++的string中的函数;与atoi不同,atoi是C语言中的
int bb = abs(stoi(b));//abs也和fabs一样,是C语言math.h中的函数
if(a.length() == b.length()){
v[aa].push_back(bb);
v[bb].push_back(aa);
}
map[aa][bb] = true;
map[bb][aa] = true;
}
scanf("%d",&k);
while(k--){
re.clear();
int aa,bb;
scanf("%d%d",&aa,&bb);
aa = abs(aa);
bb = abs(bb);
for(int i = 0;i < v[aa].size();i++){
int c = v[aa][i];
if(bb == c) continue;//易错点,别忘记判断找到的B不能是D
for(int j = 0;j < v[bb].size();j++){
int d = v[bb][j];
if(aa == d) continue;//易错点,别忘记判断找到的C不能是A
if(map[c][d]){
re.push_back(pair(c,d));
}
}
}
sort(re.begin(),re.end(),cmp);
printf("%d\n",re.size());
for(int i = 0;i < re.size();i++){
printf("%04d %04d\n",re[i].first,re[i].second);//%04d为易错点
}
}
return 0;
}
七:vector存图;利用二维数组快速判断朋友关系;vector
#include
#include
#include
#include
#include
#include
using namespace std;
struct node{
int aa,bb;
node(int a,int b):aa(a),bb(b){}
bool operator<(const node &a)const{
return aa != a.aa?aa < a.aa:bb < a.bb;
}
};
bool map[10000][10000];
int main(){
int n,m,k;
string a,b;
vector v[10000];
//memset(map,false,sizeof(map));加了这个超出内存限制
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
cin >> a >> b;//这样读取的原因是有易错点:-0000
int aa = abs(stoi(a));//stoi是C++的string中的函数;与atoi不同,atoi是C语言中的
int bb = abs(stoi(b));//abs也和fabs一样,是C语言math.h中的函数
if(a.length() == b.length()){
v[aa].push_back(bb);
v[bb].push_back(aa);
}
map[aa][bb] = true;
map[bb][aa] = true;
}
scanf("%d",&k);
while(k--){
int aa,bb;
vector re;
scanf("%d%d",&aa,&bb);
aa = abs(aa);
bb = abs(bb);
for(int i = 0;i < v[aa].size();i++){
int cc = v[aa][i];
if(bb == cc) continue;//易错点,别忘记判断找到的B不能是D
for(int j = 0;j < v[bb].size();j++){
int dd = v[bb][j];
if(aa == dd) continue;//易错点,别忘记判断找到的C不能是A
if(map[cc][dd]){
re.push_back(node(cc,dd));//node{cc,dd}也可以,C++ 11新标准
}
}
}
sort(re.begin(),re.end());
printf("%d\n",re.size());
for(int i = 0;i < re.size();i++){
printf("%04d %04d\n",re[i].aa,re[i].bb);//%04d为易错点
}
}
return 0;
}