light oj 1003—拓扑排序

题意:即找所给字符串组成的饮料名是否组成环

涉及知识:

1、链表

2、拓扑排序

3、STL  中 map、stack的应用(当然也可以自己实现,不太建议,当然没事儿写来练手当然行)

详细注释见代码:

#include<cstdio>
#include<iostream>
#include<map>
#include<stack>
#include<cstdlib>
#include<string>
#include<cstring>

using namespace std;
///链表存图
typedef struct Edge   ///一条边的后顶点
{
    int toE;
    Edge *next = NULL; ///指向下一条以Vnum为前顶点的,后定点的位置
}Edge;

typedef struct Vnum   ///每条边的前定点
{
    int data;
    Edge *firstEdge = NULL;
}Vnum;

Vnum V[10010];
int indegree[10010];///每个定点的入度
stack<int > innum;
///拓扑排序
int tuopo(int num)
{
    int countt = 0;
    memset(indegree, 0, sizeof(indegree));///初始化每个定点的入度为0
    
    ///计算每个定点的入度:
    for(int i = 0; i < num; i++)
    {
        Edge *temp = V[i].firstEdge;
        while(temp)
        {
            indegree[temp->toE]++;
            temp = temp->next;
        }
    }
    ///将入度为零的顶点入栈:
    for(int i = 0; i < num; i++)
    {
        if(indegree[i] == 0)
        {
            innum.push(i);
        }
    }
    ///将入度为0的顶点从图中一一删除,并且将与该定点有关的边都删除
    while(!innum.empty())
    {
        ///删除栈顶第一个入度为0顶点
        int topnum = innum.top();
        innum.pop();
    
        ///删除与该点有关的所有边
        Edge *temp = V[topnum].firstEdge;
        while(temp)
        {
            indegree[temp->toE]--;
            ///如果和该顶点相关联的边后, 边的另一个顶点的入度为0了,则入栈
            if(indegree[temp->toE] == 0)
            {
                innum.push(temp->toE);
            }
            temp = temp->next;
        }
        countt++;///记录删除顶点为0的顶点个数
    }

    ///若按顺序删除入度为0的顶点个数等于原图的顶点个数, 则无环;  否则有环
    if(countt == num)
        return 1;
    else
        return 0;
}
///释放链表
void Free(int num)
{
    for(int i = 0; i < num; i++)
    {
        Edge *p, *q, temp;
        p = V[i].firstEdge;
        while(p)
        {
            q = p->next;
            free(p);
            p = q;
        }
        V[i].firstEdge = NULL;
    }
    return ;
}
int main()
{
    int T, edg, num, CAS = 1;
    char s1[20], s2[20];
    
    ///使用map将字符串转化成数字
    map<string, int> str_int;

    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &edg);
        int n = edg;
        num = 0;
        str_int.clear();
        while(n--)
        {
            scanf(" %s %s", s1, s2);
            if(str_int.find(s1) == str_int.end())
            {
                str_int[s1] = num++;
            }
            if(str_int.find(s2) == str_int.end())
            {
                str_int[s2] = num++;
            }
            
            ///将s2(后顶点)所对应的顶点接到s1(前顶点)所对应的顶点后面去
            Edge *temp = (Edge*)malloc(sizeof(Edge));
            temp->toE = str_int[s2];
            temp->next = NULL;
            if(V[str_int[s1]].firstEdge == NULL)///如果s1后面还没有接点,就接到后面
            {
                V[str_int[s1]].firstEdge = temp;
            }
            else///如果已经s1后面已经有边了,则找到最后接的一个点,接到它后面
            {
                Edge *p = V[str_int[s1]].firstEdge;
                while(p->next != NULL)
                {
                    p = p->next;
                }
                p->next = temp;
            }
        }
        
        int ans = tuopo(num);
        if(ans == 1)
             printf("Case %d: Yes\n", CAS++);
        else
            printf("Case %d: No\n", CAS++);
        ///释放空间
        Free(num);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/look_poet_of_water/article/details/79164915