程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hiho拓撲排序專題 ——第四十八、四十七周,hiho拓撲排序專題

hiho拓撲排序專題 ——第四十八、四十七周,hiho拓撲排序專題

編輯:C++入門知識

hiho拓撲排序專題 ——第四十八、四十七周,hiho拓撲排序專題


 

拓撲排序·一

分析:

  此題就是求一個有向圖中是否存在環。 如存在環則輸出"Wrong", 若不存在環, 說明課程安排的合理,輸出"Correct"。

題中的提示說的已經十分清楚了。

總的來說就是

  ① 找出入度為0的點(說明該點沒有前驅),把該點放入集合T中。 把所有從該點出發的邊都刪除;

  ② 遍歷剩余的點, 找出入度為0 的點, 重復①操作。 

  ③直到不存在入度為0的點。 結束。如果此時集合T中包含所有的點, 那麼該圖不存在環, 否則存在環。

注意:1、執行操作①時, 在刪除邊時(u, v),同時更新與其相關點的入度(du[v]--);

         2、 在執行操作②時, 需要遍歷所有點, 點少的時候可行, 點多的話很容易超時。 所以題目的提示中告訴了一個好辦法就是: 執行操作①更新相關點的入度時直接判斷一下是否為0, 若為零則入隊列。 這樣會省很多時間。

如下圖例子:

開始點1入度為0, 點1加入集合T,   刪除從1出發的邊;  更新相關點的入度, 點2、3的入度都變為0了 , 2、3入隊列; 

再依次對點2、3進行①操作, 2、3加入T,   刪除邊(2, 4), (3, 4), 此時沒有其他點入度為0了, 結束操作, T中未包含所有點, 說明該圖中有環;

 

  

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

int t, n, m, sum, du[100005];
vector<int> vec[100005];

int ac()
{
    queue<int> q;
    for(int i = 1; i <= n; i++)//遍歷一邊所有點, 把入度為0的點,全加入隊列q中
    {
        if(du[i] == 0)
            q.push(i);
    }
    while(!q.empty())
    {
        int tem = q.front();//在隊列中取出一個入度為0的點
        q.pop();
        sum++;
        //把所有從tem出發的邊(tem, v)刪除並更新du[], 
        for(int i = 0; i < vec[tem].size(); i++)
        {
            du[vec[tem][i]]--;
            if(du[vec[tem][i]] == 0)//若點vec[tem][i]入度更新後為0, 則入隊列
                q.push(vec[tem][i]);
        }
        vec[tem].clear();
    }
    if(sum == n) return 1;
    else
        return 0;
}
int main()
{
    cin >> t;
    while(t--)
    {
        scanf("%d%d", &n, &m);
        //用vec[]來存邊
        for(int i = 1; i <= n; i++) vec[i].clear();
        memset(du, 0, sizeof(du));//初始化入度, 置為0;
        for(int i = 1; i <= m; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            vec[x].push_back(y); // 加入邊
            du[y]++; //記錄入度
        }
        sum = 0;
        int ans = ac();
        if(ans == 1)
            printf("Correct\n");
        else
            printf("Wrong\n");
    }
    return 0;
}

 

拓撲排序·二

分析:

 和上一道差不多, 只是多了一項就是記錄每個點的病毒數。  每個點的病毒數 = 自身病毒數 +  所有能夠達到它的節點病毒數之和( 就是所有它前驅點的病毒數的和)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int mod = 142857;
int n, m, k, sum, virus[100005], du[100005];
vector<int> vec[100005];

void ac()
{
    queue<int> q;
    for(int i = 1; i <= n; i++)
    {
        if(du[i] == 0)
            q.push(i);
    }
    while(!q.empty())
    {
        int tmp = q.front(); q.pop();
        sum = (sum + virus[tmp]) % mod;  
        
        //把所有前驅點為 tmp 的點的病毒數都加上 tmp的病毒數
        for(int i = 0; i < vec[tmp].size(); i++)
        {
            int b = vec[tmp][i];
            virus[b] = (virus[tmp] + virus[b]) % mod;// 此處也一定要取模,
            du[b]--;
            if(du[b] == 0)
                q.push(b);
        }
        vec[tmp].clear();
    }
}
int main()
{
    while(scanf("%d%d%d", &n, &m, &k) != EOF)
    {
        memset(virus, 0, sizeof(virus));
        memset(du, 0, sizeof(du));
        for(int i = 1; i <= n; i++) vec[i].clear();

        for(int i = 1; i <= k; i++)
        {
            int x;
            scanf("%d", &x);
            virus[x]++;
        }
        for(int i = 1; i <= m; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            vec[x].push_back(y);
            du[y]++;
        }

        sum = 0;
        ac();
        printf("%d\n", sum);
    }
    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved