1. 程式人生 > >拓撲排序 HDU - 5695

拓撲排序 HDU - 5695

+= ret include pty pri 包括 log const bin

眾所周知,度度熊喜歡各類體育活動。

今天,它終於當上了夢寐以求的體育課老師。第一次課上,它發現一個有趣的事情。在上課之前,所有同學要排成一列, 假設最開始每個人有一個唯一的ID,從1到NN,在排好隊之後,每個同學會找出包括自己在內的前方所有同學的最小ID,作為自己評價這堂課的分數。麻煩的是,有一些同學不希望某個(些)同學排在他(她)前面,在滿足這個前提的情況下,新晉體育課老師——度度熊,希望最後的排隊結果可以使得所有同學的評價分數和最大。

Input第一行一個整數TT,表示T(1T30)T(1≤T≤30) 組數據。

對於每組數據,第一行輸入兩個整數NN和M(1N100000,0M100000)M(1≤N≤100000,0≤M≤100000),分別表示總人數和某些同學的偏好。

接下來

MM行,每行兩個整數AA 和B(1A,BN)B(1≤A,B≤N),表示ID為AA的同學不希望ID為BB的同學排在他(她)之前。你可以認為題目保證至少有一種排列方法是符合所有要求的。
Output對於每組數據,輸出最大分數 。Sample Input

3
1 0
2 1
1 2
3 1
3 1

Sample Output

1
2
6
對於這個題目來說,顯然可以看出這是有限制關系的偏序排序題目,拓撲排序的思想自然而然,想到思路並不難沒重點是如何處理程序並將程序寫出來;
根據個人習慣,把理解加在代碼註釋裏面。
#include <iostream>
#include <string>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 100010;
const int inf  = 0x3f3f3f3f3f;
vector<int> G[maxn];//由於直接用int G[maxn][maxn] 會占用大內存,有可能會爆
int indegree[maxn];//這是對點的入度標記
int main()
{
    int T;
    scanf("%d",&T);
    int n,m;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(indegree,0,sizeof(indegree));//清空處理,同下
        memset(G,0,sizeof(G));//第二階段代碼會對這一點進行優化;
        int u,v;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            G[u].push_back(v);//和點u,存在偏序關系的點 v,壓入
            indegree[v]++;//哈希圖特點,偏序關系,由u->v,點v的入度++,不需要考慮出度
        }//具體可以參考另一篇博文
        priority_queue<int> que;//優先隊列對壓入的點進行維護
        //優先隊列默認是大的在前,也就是降序
        for(int k=1;k<=n;k++)
            if(!indegree[k]) que.push(k);//先將沒有入度的點壓入,
        //沒有入度的點,也就是不存在以該點為終點的偏序關系,對整體排序沒有影響
        //在哈希圖上體現就是(假設哈希圖由下往上繪制),這個點是懸掛點,極小點(離散數學)
        long long res=0;//long long 保險,看題目吧
        int u_num=inf;//考慮程序的魯棒性,定義為無限大
        while(!que.empty())//隊列的維護+模擬過程
        {
            int num=que.top();//頭,是不是有點像bfs,這就對了
            que.pop();//就按照bfs代碼方式搞下去,部分改變
            u_num=min(u_num,num);
            res+=u_num;
            for(int i=0;i<G[num].size();i++)
            {
                int v=G[num][i];//這是對該點排序後,刪除所有把該點作為起點的線段
                //也可以理解為,除去哈希圖上的這個點->哈希圖不允許懸掛邊的存在
                indegree[v]--;//對應的終點入度--
                if(!indegree[v])//入度為0,對後續排序沒影響,選擇壓入
                    que.push(v);
            }
        }
        printf("%lld\n",res);//輸出總花費
    }
}

  運行702ms;

其實可以看出來memset遍歷清空費的時間是比較大的,可以根據vector特點修改下(借鑒了求前輩的博文)

#include <iostream>
#include <string>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 100010;
const int inf  = 0x3f3f3f3f3f;
vector<int> G[maxn];
int indegree[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    int n,m;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++) {
            indegree[i] = 0;
            G[i].clear();
        }
        int u,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            indegree[v]++;
        }
        priority_queue<int> que;
        for(int k=1;k<=n;k++)
            if(!indegree[k]) que.push(k);
        long long res=0;
        int u_num=inf;
        while(!que.empty())
        {
            int num=que.top();
            que.pop();
            u_num=min(u_num,num);
            res+=u_num;
            for(int i=0;i<G[num].size();i++)
            {
                int v=G[num][i];
                indegree[v]--;
                if(!indegree[v])
                    que.push(v);
            }
        }
        printf("%lld\n",res);
    }
}

  608ms;確實,有點效果;

不知道之前我的拓撲你們看了沒,請看如下代碼;

#include <iostream>
#include <string>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 100010;
const int inf  = 0x3f3f3f3f3f;
vector<int> G[maxn];
int indegree[maxn];
priority_queue<int> que;
void combine(int a,int b)
{
    G[a].push_back(b);
    indegree[b]++;
    return;
}
void del_gre(int num)
{
    for(int i=0;i<G[num].size();i++)
    {
        int v=G[num][i];
        indegree[v]--;
        if(!indegree[v])
           que.push(v);
    }
    return;
}
int main()
{
    int T;
    scanf("%d",&T);
    int n,m;
    while(T--)
    {
        while(!que.empty())
            que.pop();
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++) {
            indegree[i] = 0;
            G[i].clear();
        }
        int u,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            combine(u,v);
        }

        for(int k=1;k<=n;k++)
            if(!indegree[k]) que.push(k);
        long long res=0;
        int u_num=inf;
        while(!que.empty())
        {
            int num=que.top();
            que.pop();
            u_num=min(u_num,num);
            res+=u_num;
            del_gre(num);
        }
        printf("%lld\n",res);
    }
}

  根據我上個關於拓撲理解寫的

670ms;

最後來一句,求關註~’

拓撲排序 HDU - 5695