拓扑排序(主要是确定环和加法) HDU 2647 Reward

这道题数据比较大,得用领阶表,表示压力很大。。。。

这道题有两个地方值得注意。

第一个地方就是怎么确定是否有环,确定的办法就是就是根据离散数学(离散86,烧包加雄起~)的入度来说,当遍历一边并且更新后查找入度为零的点应该有N个(一共N个点)。用一个计数器num去计算是否为n。

第二个地方就是方向思维。按理说我们应该用大的作小的父亲,但是当我们建立完一个拓扑表以后,我们如果按照以大的作为父亲的话,我们在计算最顶端的权值(暂且叫为权值吧),即最高点的薪水时,用起点与后续节点相比较加一时不准的,因为后面节点的值会随着向后遍历而改变,而对于遍历完的值无法改变。所以我们不如去找最为固定的点,即最小薪水的点,来一次往上去寻找,也就是用了DP中从下而上的逆向思想,来计算总薪水。

但是有人会担心,即使如此也可能使得已被遍历过的值不在改变,从而不能保证结果的准确性。比如这个数据:

4 4(4个数,4个关系)

2 1

3 1

3 2

1 4

从1开始遍历的话,到了2,3组数据可以没问题,但是最后一组呢???请记住,我们是按拓扑排序的最低点出发,即4,入度为零的点开始搜索遍历。这样就没有问题了。

以下是代码

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 struct node
 4 {
 5     int u,v;
 6     int next;
 7 }g[20005];//
 8 struct degree
 9 {
10     int i,w;
11 } head[10005];//头结点,也就是有多少个点。
12 int t,count;
13 int in[10005];//记录入度。
14 void init(int n)
15 {
16     int i;
17     for(i = 0;i <= n;i++)
18     head[i].i = -1,head[i].w = 888,in[i] = 0;
19     t = 0;
20 }
21 void add(int u,int v)//加入边,建立关系。分清谁是该节点的代表值,谁是子节点。
22 {
23     in[u]++;//子节点的入度+1;
24     g[t].u = u;
25     g[t].v = v;
26     g[t].next = head[v].i;
27     head[v].i = t;//v才是父亲
28     t++;
29 }
30 
31 int main()
32 {
33     int n,m,i,j,u,v,num,p;
34     while(~scanf("%d %d",&n,&m))
35     {
36         init(n);
37         for(i = 0;i < m;i++)
38         {
39             scanf("%d %d",&u,&v);
40             add(u,v);//v才是父亲
41         }
42         num = n;//给计数器赋值
43         for(i = 0;i < n;i++)
44         {
45             for(j = 1;j <= n;j++)
46             {
47                 if(in[j] == 0)
48                 {
49                     num--;//出现符合节点,计数器减一。
50                     in[j] = -1;
51                     break;
52                 }
53             }
54             if(j > n)
55             break;
56             p = head[j].i;
57             while(p != -1)
58             {
59                 in[g[p].u]--;
60                 if(head[g[p].u].w <= head[j].w)
61                 head[g[p].u].w = head[j].w+1;
62                 p = g[p].next;
63             }
64         }
65         int sum;
66         sum = 0;
67         if(num)//说明出现了环。
68         puts("-1");
69         else {
70             for(i = 1;i <= n;i++) sum+=head[i].w;
71             printf("%d\n",sum);
72         }
73     }
74 }
原文地址:https://www.cnblogs.com/0803yijia/p/2620689.html