1. 程式人生 > >HDU 2647 拓撲排序分層;

HDU 2647 拓撲排序分層;

Problem Description

Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wants to distribute rewards to his workers. Now he has a trouble about how to distribute the rewards.
The workers will compare their rewards ,and some one may have demands of the distributing of rewards ,just like a's reward should more than b's.Dandelion's unclue wants to fulfill all the demands, of course ,he wants to use the least money.Every work's reward will be at least 888 , because it's a lucky number.

Input

One line with two integers n and m ,stands for the number of works and the number of demands .(n<=10000,m<=20000)
then m lines ,each line contains two integers a and b ,stands for a's reward should be more than b's.

Output

For every case ,print the least money dandelion 's uncle needs to distribute .If it's impossible to fulfill all the works' demands ,print -1.

Sample Input

2 1

1 2

2 2

1 2

2 1

Sample Output

1777

-1

分析:

 其實就是將所有員工的獎金拓撲排序,然後從888開始安排.不過要注意對於任意獎金數(比如889或888)可能有多個員工獲得同樣的獎金.

        實現方法很多,這裡我採用網上一位大牛的方法.將整個拓撲圖分層,位於第0層的是那些可以獲得888獎金的,位於第1層的是可以獲得889獎金的,依次類推.最終的獎金總數就是888*N+(所有節點層數總和).

 

程式碼:

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=10000+10;
const int maxm=20000+10;
int n,m;
int ans;        //ans記錄所有節點層數dep的總和
struct Node
{
    int in,dep; //入度與層號
    int head;   //指向第一條邊號,head為0表示無邊
}nodes[maxn];
struct Edge
{
    int to;     //尾節點  
    int next;   //下一條邊  ,相當於鄰接表裡的next陣列。
}edges[maxm];   //邊從1開始計數
void add_edge(int i,int u,int v)//新增一條從u->v的邊
{
    edges[i]=(Edge){v,nodes[u].head};
    nodes[u].head=i;
    nodes[v].in++;
}
bool topo()
{
    queue<int> Q;
    ans=0;
    int sum=0;
    for(int i=1;i<=n;i++)if(nodes[i].in==0)
        Q.push(i);
    while(!Q.empty())
    {
        int u=Q.front(); Q.pop();
        sum++;
        ans+= nodes[u].dep;
        for(int e=nodes[u].head;e;e=edges[e].next)
        {
            int v=edges[e].to;
            if(--nodes[v].in==0)//這裡要注意:若u是正好能使得v入度歸0的點,那麼u一定是所有指向v點的點中深度最大的
            {
                Q.push(v);
                nodes[v].dep = nodes[u].dep+1;
            }
        }
    }
    return sum==n;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(nodes,0,sizeof(nodes));
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(i,v,u);
        }
        printf("%d\n",topo()?888*n+ans:-1);
    }
    return 0;
}

鄰接表詳解----->這裡