1. 程式人生 > 實用技巧 >PAT甲級1139First Contact

PAT甲級1139First Contact

題目連結

https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312

題解

題目要求

  • 背景

    男生A喜歡女孩B,A找男生C讓女孩D跟B說,其中C是A的朋友,D是B和C的朋友。女生也是這樣聯絡男生

  • 輸入

    • N:人的數量,1到300
    • M:朋友關係的數量
    • M個朋友關係:用4位數字表示一個人,其中負數代表性別是女生
    • K:查詢數量,不超過100
    • K次查詢:每次查詢是A和B的ID,假設A喜歡B
  • 輸出

    • 輸出有幾對C和D可以幫助A聯絡B

    • 輸出這幾對C和D

      • 如果A和B是異性,則A和C應該是同性,B和D同性;如果A和B是同性,則這4人性別應該相同

        即A和C同性,B和D同性

      • 先按C的ID非降序輸出,再按D的ID增序輸出

思路

  1. 使用鄰接矩陣表示兩個人是否是朋友,用鄰接表儲存一個人的同性朋友
  2. 給定A和B以後,列舉A的朋友C,列舉B的朋友D,如果C和D是朋友則儲存C和D

注意點

  • 輸出時要以4位數字輸出,用printf("%04d"),第二和第三個測試點都測試了這個
  • 如果用int接收一對朋友,-0000和0000對於int來說都是0,將無法得知這個人的性別
    • 在這裡我對他們的id進行了處理:把女生對映到[0,9999],男生對映到[10000,19999]
    • 也可以使用其他的雜湊方法
  • 正常回路為A-C-D-B,不可以形成A-B-D-B或A-C-A-B的迴路,即AD不相等、BC不相等
  • 寫迴圈程式碼時注意一些變數是否會隨著迴圈執行而改變,比如陣列大小、外層迴圈變數是否被內層迴圈改變

程式碼

// Problem: PAT Advanced 1139
// URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312
// Tags: Graph Hash

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

bool isFriend[20000][20000]; // 鄰接矩陣
vector<int> friends[20000]; // 鄰接表,同性朋友

struct Helper{
    int c, d;
};

int transform(string s){
    // 將負數對映到[0,9999],將正數對映到[10000,19999]
    if (s[0] == '-')
        return abs(stoi(s));
    else
        return 10000 + stoi(s);
}

int restore(int num){
    // 將transform得到的[0,19999]的數字對映到[0,9999],即原來的[-9999,9999]取絕對值得到[0,9999],以進行輸出
    if (num > 9999)
        return num - 10000;
    else
        return num;
}

bool helperCmp(Helper& h1, Helper& h2){
    return h1.c == h2.c ? h1.d < h2.d : h1.c < h2.c;
}

int main()
{
    int n, m, k, a, b, c ,d;
    string s, t;
    scanf("%d %d", &n, &m);

    for (int i = 0; i < m; i++){ // 將圖存入鄰接矩陣和鄰接表
        cin >> s >> t;
        a = transform(s);
        b = transform(t);
        isFriend[a][b] = isFriend[b][a] = true;
        if ( (a<10000 && b<10000) || (a>9999 && b>9999) ){ // 同性則儲存到鄰接表
            friends[a].push_back(b);
            friends[b].push_back(a);
        }
    }

    scanf("%d", &k);
    while (k--){
        cin >> s >> t;
        a = transform(s);
        b = transform(t);
        vector<Helper> helpers;
        for (auto it1 = friends[a].begin(); it1 != friends[a].end(); it1++){
            c = *it1;
            if (c == b) // C和B不能是一個人
                continue;
            for (auto it2 = friends[b].begin(); it2 != friends[b].end(); it2++){
                d = *it2;
                if (d == a) // D和A不能是一個人
                    continue;
                if (isFriend[c][d])
                    helpers.push_back({restore(c), restore(d)});
            }
        }
        sort(helpers.begin(), helpers.end(), helperCmp);
        printf("%d\n", helpers.size());
        for (auto it = helpers.begin(); it != helpers.end(); it++)
            printf("%04d %04d\n", it->c, it->d);
    }

    return 0;
}

一份超時的程式碼

// Problem: PAT Advanced 1139
// URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312
// Tags: Graph Hash Map

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
using namespace std;

struct Helper{
    string c, d;
};

bool helperCmp(Helper& h1, Helper& h2){
    return abs(stoi(h1.c)) == abs(stoi(h2.c)) ? abs(stoi(h1.d)) < abs(stoi(h2.d)) : abs(stoi(h1.c)) < abs(stoi(h2.c));
}

int main()
{
    int n, m, k;
    string a, b, c, d;
    unordered_map<string, vector<string>> friends; // 會很耗時
    scanf("%d %d", &n, &m);

    for (int i = 0; i < m; i++){ // 儲存朋友關係
        cin >> a >> b;
        if (a[0] != '-')
            a = '+' + a;
        if (b[0] != '-')
            b = '+' + b;
        friends[a].push_back(b);
        friends[b].push_back(a);
    }
    
    scanf("%d", &k);
    while (k--){
        cin >> a >> b; // a喜歡b
        if (a[0] != '-')
            a = '+' + a;
        if (b[0] != '-')
            b = '+' + b;
        vector<Helper> helpers;
        // 下邊這個大的for迴圈也很耗時間
        for (auto it1 = friends[a].begin(); it1 != friends[a].end(); it1++){
            c = *it1; // a的朋友c
            if (b == c || a[0] != c[0]) // a和c不可以是同一個人,且應該是同性
                continue;
            for (auto it2 = friends[c].begin(); it2 != friends[c].end(); it2++){
                d = *it2; // c的朋友d
                if (a == d || b[0] != d[0]) // a和d不可以是同一個人,且應該是同性
                    continue;
                if (find(friends[d].begin(), friends[d].end(), b) != friends[d].end()){
                    helpers.push_back({c, d});
                }
            }
        }
        sort(helpers.begin(), helpers.end(), helperCmp); // 按id升序儲存,達到題目輸出要求
        int num = helpers.size();
        printf("%d\n", num);
        for (int i = 0; i < num; i++)
            printf("%04d %04d\n", abs(stoi(helpers[i].c)), abs(stoi(helpers[i].d)));
    }
    return 0;
}

參考連結

https://blog.csdn.net/liuchuo/article/details/79065004


作者:@臭鹹魚

轉載請註明出處:https://www.cnblogs.com/chouxianyu/

歡迎討論和交流!