小米2015校招(2014-9-25合肥) 排队 图 有向图是否存在回路 拓扑排序

这篇博客讨论了小米2015年校招中遇到的一个排队问题,该问题涉及有向图和拓扑排序。通过给定的Request和Apply结构体,需要确定是否能按照特定条件安排人员顺序,即图是否存在回路。博主提出使用拓扑排序来判断,并提供了严蔚敏《数据结构(C语言版)》中的算法思路和邻接表存储方法。同时,给出了测试用例及结果,展示了解决方案的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跟这位博友碰到的题目一样:http://blog.youkuaiyun.com/u013088799/article/details/39587403

简单的说就是,几千人要排成一队。有些人要求某些人一定要排在自己前面,某些人一定要排在自己后面。问是否有解,有则给出一个解。

给定的几个预定义结构体、函数原型如下:

typedef struct Request{
    string owner;         //对某人
    bool   frontOrBehind; // true 本owner在前applicant申请人之前;;false:本owner在申请人之后
}Request; //

typedef struct Apply{
    string applicant;    //申请者
    list<Request> requests;   //
}Apply;

 

list<string>  getValidSeq(list<string>& allMembers,list<Apply>& allApply)

 

解题思路:判断有向图是否存在回路,显然使用拓扑排序比使用深度(广度)搜索要好些。具体算法是 严蔚敏《数据结构(C语言版)》拓扑排序章节、存储图用 邻接表。

代码如下:

#include<iostream>
#include<cstdio>
#include<string>
#include<list>
#include<hash_map>
#include<cstdlib>
#include<queue>

using namespace std;
#define MAX_VERTEX_NUM (10000)
typedef struct Request{
    string owner;         //对某人
    bool   frontOrBehind; // true 本owner在前applicant申请人之前;;false:本owner在申请人之后
    Request(string owner,bool frontOrBehind):owner(owner),frontOrBehind(frontOrBehind){}
}Request;

typedef struct Apply{
    string applicant;    //申请者
    list<Request> requests;   //
}Apply; 

typedef struct ArcNode{
    int adjVex;
    ArcNode * nextArc;
   //该弧信息(或其指针)
    ArcNode(){nextArc = NULL;}
}ArcNode;

typedef struct VNode{
    //顶点信息(或其指针)
    string   name;
    ArcNode  *firstArc;
    VNode() {firstArc = NULL;}
}VNode,AdjList[MAX_VERTEX_NUM];

list<string> getValidSeq(list<string>& allMembers,list<Apply>& allApply){
    hash_map<string,int>  name2id;              //哈希容器,快速取得编号
    AdjList  adjList;                           //邻接表
    int inDegreeOfNodes[MAX_VERTEX_NUM]={0};    //记录每个顶点入度,初始化为0
    int numOfAll = allMembers.size();
    list<string>::iterator iter_mem = allMembers.begin();
    for(int i=0;iter_mem != allMembers.end();iter_mem++,i++){
        name2id[*iter_mem] = i;
        (adjList[i]).name = *iter_mem;
    }

    list<Apply>::iterator iter_apply = allApply.begin();
    list<Request>::iterator iter_req;
    for(int i=0;iter_apply != allApply.end();iter_apply++){
        int idOfApplier = name2id[iter_apply->applicant];
        list<Request>::iterator iter_req = iter_apply->requests.begin();
        for( ;iter_req != iter_apply->requests.end();iter_req++){
            int idOfRef = name2id[iter_req->owner];
            int id_front,id_behind;
            if(iter_req->frontOrBehind){
                id_front = idOfRef;
                id_behind = idOfApplier;
            }
            else{
                id_front = idOfApplier;
                id_behind = idOfRef;
            }
            ArcNode * ptr =  adjList[id_front].firstArc;
            while(ptr && ptr->nextArc)
                ptr = ptr->nextArc;
            ArcNode * newArc = (ArcNode*)malloc(sizeof(ArcNode));
            newArc->adjVex = id_behind;
            newArc->nextArc = NULL;
            if(!ptr)
                adjList[id_front].firstArc = newArc;
            else
                ptr->nextArc = newArc;
            inDegreeOfNodes[id_behind]++;   //统计入度
        }
    }

    queue<int> degZeroNodes;

    list<string> result;
    int cnt = 0;
    for(int i=0;i<numOfAll;i++){
        if(!inDegreeOfNodes[i])
            degZeroNodes.push(i);
    }
    while(!degZeroNodes.empty()){
        int curId = degZeroNodes.front();
        result.push_back(adjList[curId].name);
        degZeroNodes.pop();
        ArcNode *ptr = adjList[curId].firstArc;
        while(ptr){
            int id = ptr->adjVex;
            inDegreeOfNodes[id]--;
            if(! inDegreeOfNodes[id])
                degZeroNodes.push(id);
            ptr = ptr->nextArc;
        }
        cnt++;
    }
    //free 
    for(int i=0;i<numOfAll;i++){
        ArcNode *ptr = adjList[i].firstArc,*next;
        while(ptr){
            next = ptr->nextArc;
            free(ptr);
            ptr = next;
        }
    }

    if(cnt<numOfAll){    //NULL 不存在合法解
        result.clear();
        return result;
    }
    return result;
}
/*
*   制定输入信息格式为:
*    总共人数(n)
*    n 个人人名
*    提出申请的人数
*    申请人姓名 放在自己前面的人数 后面的人数  放在自己前面的人名 放在自己后面的人名 
*/
int main(){
    list<string> members;
    list<Apply>  applies;
    list<string> result;

    freopen("input.txt","r",stdin);   

    int numOfMem,numOfApply;

    while(cin>>numOfMem){
        members.clear();
        applies.clear();
        result.clear();
        for(int i=0;i<numOfMem;i++){
            string name;
            cin>>name;
            members.push_back(name);
        }
        cin>>numOfApply;
        for(int i=0;i<numOfApply;i++){
            string applier;
            int numFront,numBehind;
            cin>>applier>>numFront>>numBehind;
            Apply myApply;
            myApply.applicant = applier;

            for(int j=0;j<numFront;j++){
                string name;
                cin>>name;
                myApply.requests.push_back(Request(name,true));
            }
            for(int k=0;k<numBehind;k++){
                string name;
                cin>>name;
                myApply.requests.push_back(Request(name,false));
            }
            applies.push_back(myApply);
        }

        result = getValidSeq(members,applies);
        if(result.empty())
            cout<<"NO SOLUTION!!!"<<endl;
        else{
            for(list<string>::iterator iter_result = result.begin();iter_result!=result.end();iter_result++)
                cout<<*iter_result<<" ";
            cout<<endl;
        }
    }
}


 

测试用例如下:

10
a b c d e f g h i j
2
b 2 2   e f     i j
c 2 2   g h     a b


10
a b c d e f g h i j
3
b 2 2   e f     i j
c 2 2   g h     a b
g 1 1   i       a

 

测试用例得到结果如下:

d e f g h c a b i j
NO SOLUTION!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值