有向图 & 无向图 环判断

公司成天坑爹考试;不过我下个月才考。闲来无事,写个算法玩玩。

PS,公司坑爹,不让用stl;所以用一个数组来替代stl::stack。

++++++++++++++++++++++++++++++++++++

#无向图

无向图比较简单,只需要用一个辅助的 Visit 数据记录点是否被访问过即可。

#include <iostream>
//#include <stack>

using namespace std;

#define T_LEN 301

int Answer;    //0: has no circle; 1: has circle;
int N, E;    //N: number of point; E: number of edge;
int Edge[T_LEN][T_LEN];
int Visit[T_LEN];    //has been visited or not
//stack<int> SCircle;
int SCircle[T_LEN];    //store the circle
int g_index;    //key point of circle (position)
int g_circle_item;    //the key point of circle (value)

//trave Graphic from '_index';
//if has circle, return 1; else, return 0 to continue;
int TVisit(int _index)
{
    int res = 0;
    int j;
    int ind = _index;

    if (1 == Visit[ind])
    {
        res = 1;
    }
    else
    {
        Visit[ind] = 1;
        SCircle[g_index++] = ind;
        for (j = 1; j <= N; j++)
        {
            if (1 == Edge[ind][j])
            {
                Edge[ind][j] = Edge[j][ind] = 0;
                if (1 == Visit[j])
                {
                    res = 1;
                    SCircle[g_index] = j;
                    g_circle_item = j;
                    break;
                }
                else
                {
                    if (TVisit(j) == 1)
                    {
                        res = 1;
                        break;
                    }
                    else
                    {
                        //popup stack
                        SCircle[g_index-1] = 0;
                        g_index--;
                    }
                }
            }
        }
    }
    return res;
}

void TCase(int _index)
{
    int i, j;
    int a, b;

    //input & init
    cin >> N >> E;
    for (i = 1; i <= N; i++)
    {
        Visit[i] = 0;
        SCircle[i] = 0;        
        for (j = 1; j <= N; j++)
        {
            Edge[i][j] = 0;
        }
    }
    for (i = 0; i < E; i++)
    {
        cin >> a >> b;
        Edge[a][b] = Edge[b][a] = 1;
    }
    g_index = 0;
    //processing
    for (i = 1; i <= N; i++)
    {
        if (Visit[i] == 0)
        {
            //has not visited; then traverse the graphics from 'i';
            Answer = TVisit(i);
            if (Answer == 1)
            {
                //print circle
                j = g_index - 1;
                while (SCircle[j] != g_circle_item)    j--;
                for (; j <= g_index; j++)
                {
                    cout << SCircle[j] << " ";
                }
                break;
            }
        }
    }
}

int main(void)
{
    int i, T;

    freopen("graphics.txt", "r", stdin);
    cin >> T;
    for (i = 0; i < T; i++)
    {
        cout << "Case " << i + 1 << "# ";
        Answer = 0;
        TCase(i);
        cout << ( (Answer == 1) ? "has " : "has no " ) << "circle" << endl;        
    }
    return 0;
}

++++++++++++++++++++++++++++++++++++

#有向图

一开始也尝试用DFS的方式(和无向图一样)来判断环,但发现还是有一些差别的。

后来搜了下,才知道每个顶点的状态不对。

图中的一个节点,根据其C[N]的值,有三种状态:
    0,此节点没有被访问过
    -1,被访问过至少1次,其后代节点正在被访问中
    1,其后代节点都被访问过。

    按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能:
    1、如果C[V]=0,这是一个新的节点,不做处理
    2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。
    3、如果C[V]=1,类似于2的推导,没有环。
#include <iostream>
//#include <stack>

using namespace std;

#define T_LEN 301

int Answer;    //0: has no circle; 1: has circle;
int N, E;    //N: number of point; E: number of edge;
int Edge[T_LEN][T_LEN];
int Visit[T_LEN];    //has been visited
//stack<int> SCircle;
int SCircle[T_LEN];
int g_index;
int g_circle_item;

//trave Graphic from '_index';
//if has circle, return 1; else, return 0 to continue;
int TVisit(int _index)
{
    int res = 0;
    int j;
    int ind = _index;

    Visit[ind] = -1;

    SCircle[g_index++] = ind;

    for (j = 1; j <= N; j++)
    {            
        if (1 == Edge[ind][j])
        {
            if (Visit[j] == -1)
            {
                //find circle
                res = 1;
                SCircle[g_index] = j;
                g_circle_item = j;
                goto TVisit_END;
            }
            else if (Visit[j] == 0)
            {
                //has no visited
                if (TVisit(j) == 1)
                {
                    res = 1;
                    goto TVisit_END;
                }
                else
                {
                    SCircle[g_index - 1] = 0;
                    g_index--;
                }
            }            
        }
    }//for
    Visit[ind] = 1;

TVisit_END:
    return res;
}

void TCase(int _index)
{
    int i, j;
    int a, b;

    //input & init
    cin >> N >> E;
    for (i = 1; i <= N; i++)
    {
        Visit[i] = 0;
        SCircle[i] = 0;        
        for (j = 1; j <= N; j++)
        {
            Edge[i][j] = 0;
        }
    }
    for (i = 0; i < E; i++)
    {
        cin >> a >> b;
        Edge[a][b] = 1;
    }
    g_index = 0;
    //processing
    for (i = 1; i <= N; i++)
    {
        if (Visit[i] == 0)
        {
            //has not visited; then traverse the graphics from 'i';
            Answer = TVisit(i);
            if (Answer == 1)
            {
                //print circle
                for (j = 0; j <= g_index;j++)
                    cout << SCircle[j] << " ";
                break;
            }
        }
    }
}

int main(void)
{
    int i, T;
    freopen("graphics_ex.txt", "r", stdin);
    cin >> T;
    for (i = 0; i < T; i++)
    {
        cout << "Case " << i + 1 << "# ";
        Answer = 0;
        TCase(i);        
        cout << ( (Answer == 1) ? "has " : "has no " ) << "circle" << endl;        
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/bouygues/p/4664985.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值