• PAT.1139 First Contact


    PAT.1139 First Contact

    题目链接

    a如果喜欢b,需要找一个自己的同性朋友c去联系一个b的同性朋友d,同时要求cd为朋友,给定图和若干查询,求每个查询下所有可能的{c,d}。

    基于图的题目一开始想到的还是那老几样————各种搜索和最短路算法,显然这道题就是要求顶点ab之间的一条长度为3的路径,同时对cd两顶点的性别作出要求。

    一些尝试

    按照上面的思路,用dfs写了一手,测试点2答案错误的同时测试点5超时。其中测试点2的问题应该是关于id为0000的情况,因为用整形保存性别信息的话-0和0都是0。

    以下代码得分24/30

    #include
    
    using namespace std;
    typedef long long ll;
    
    int peopleCnt,relationCnt,queryCnt,tId1,tId2,gender1,gender2,vis[20005];
    vector<int> neighbor[20005];
    vector<int> pathForSearch;
    vector<pair<int,int> > res;
    
    void dfs(int cVertex){
        int len = pathForSearch.size();
        if(len == 4 && pathForSearch.back() == tId2){
            res.push_back({pathForSearch[1],pathForSearch[2]});
            return;
        }else if(pathForSearch.back() == tId2) return;
        
        for(int nextVertexId : neighbor[cVertex]){
            int cGender = (nextVertexId <= 9999 ? 1 : 0);
            if(len == 1 && cGender != gender1) continue;
            if(len >= 2 && cGender != gender2) continue;
            if(vis[nextVertexId] == 1) continue;
            vis[nextVertexId] = 1;
            pathForSearch.push_back(nextVertexId);
            dfs(nextVertexId);
            pathForSearch.pop_back();
            vis[nextVertexId] = 0;
        }
    }
    
    int main(){
        cin>>peopleCnt>>relationCnt;
        for(int i = 0 ; i < relationCnt ; ++i){
            cin>>tId1>>tId2;
            tId1 += 10000;
            tId2 += 10000;
            neighbor[tId1].push_back(tId2);
            neighbor[tId2].push_back(tId1);
        }
        
        cin>>queryCnt;
        for(int i = 0 ; i < queryCnt ; ++i){
            res.clear();
            memset(vis,0,sizeof(vis));
            cin>>tId1>>tId2;
            tId1 += 10000;
            tId2 += 10000;
            gender1 = (tId1 <= 9999 ? 1 : 0);
            gender2 = (tId2 <= 9999 ? 1 : 0);
            vis[tId1] = 1;
            pathForSearch.push_back(tId1);
            dfs(tId1);
            pathForSearch.pop_back();
            vis[tId1] = 0;
            sort(res.begin(),res.end(),[](const auto &a,const auto &b){
                int a1 = abs(a.first - 10000), a2 = abs(a.second - 10000);
                int b1 = abs(b.first - 10000), b2 = abs(b.second - 10000);
                if(a1 < b1) return true;
                else if(a1 == b1 && a2 < b2) return true;
                else return false;
            });
            cout<<res.size()<<endl;
            for(auto p : res){
                printf("%04d %04d\n",abs(p.first - 10000),abs(p.second - 10000));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    题解

    站在效率的角度出发,dfs本质上搜索了所有可能的路径,而递归的效率甚至差于迭代————嗨呀,那为什么不直接枚举呢。

    首先用字符串来存储id的性别信息来排除0000的问题,然后通过在录入图的时候记录每个结点的同性别邻居————为的是在枚举时只枚举同性朋友。

    然后用一个map来保存邻接信息————这里我用map是为了枚举的时候查询方便,不过空间开销会很大,如果用把二维id映射到一维数组的方法做hash的话当然是最好的,或者直接用邻接表在用的时候再次遍历查询也行。

    最后再注意两点:

    • 在枚举两人的同性朋友的过程中恰好枚举到了对方的情况要跳过。
    • id是可能有前导0的四位id,不要因为样例而忽略了这点。
    #include
    
    using namespace std;
    typedef long long ll;
    
    int peopleCnt,relationCnt,queryCnt,tId1,tId2;
    string sId1,sId2;
    map<int,int> neighbor[20005];
    vector<int> sameGenderNeighbor[20005];
    vector<pair<int,int>> res;
    
    int main(){
        cin>>peopleCnt>>relationCnt;
        for(int i = 0 ; i < relationCnt ; ++i){
            cin>>sId1>>sId2;
            tId1 = stoi(sId1) + 10000;
            tId2 = stoi(sId2) + 10000;
            neighbor[tId1][tId2] = neighbor[tId2][tId1] = 1;
            if(sId1.size() == sId2.size()){
                sameGenderNeighbor[tId1].push_back(tId2);
                sameGenderNeighbor[tId2].push_back(tId1);
            }
        }
        cin>>queryCnt;
        for(int i = 0 ; i < queryCnt ; ++i){
            cin>>tId1>>tId2;
            tId1 += 10000;
            tId2 += 10000;
            res.clear();
            //枚举两个人的同性朋友
            for(int friend1 : sameGenderNeighbor[tId1]){
                for(int friend2 : sameGenderNeighbor[tId2]){
                    if(friend1 == tId2 || friend2 == tId1) continue;
                    if(neighbor[friend1][friend2] == 1) res.push_back({abs(friend1 - 10000),abs(friend2 - 10000)});
                }
            }
            sort(res.begin(),res.end(),less<>());
            cout<<res.size()<<endl;
            for(auto p : res){
                printf("%04d %04d\n",p.first,p.second);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
  • 相关阅读:
    车间调度|基于帝王蝶优化算法的车间调度(Matlab代码实现)
    【ARM微型电脑/IoT设备/嵌入式】树莓派安装失败sysstat,成功后还是无法使用sar,并报错:-bash:sar:command not found
    Thymeleaf学习(2)—— 流程控制
    git master回退到某个版本
    Vue——video标签实现不静音自动播放
    【目标检测】Fast R-CNN论文详细解读
    学习记忆——宫殿篇——记忆宫殿——记忆桩——学校
    查看进程与线程
    04【Redis的持久化机制】
    【C++深入学习】类和对象(一)
  • 原文地址:https://blog.csdn.net/weixin_43662405/article/details/126878687