zoukankan      html  css  js  c++  java
  • 拓扑排序(主要是确定环和加法) 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 }
  • 相关阅读:
    HDU 5791 Two (DP)
    POJ 1088 滑雪 (DPor记忆化搜索)
    LightOJ 1011
    POJ 1787 Charlie's Change (多重背包 带结果组成)
    HDU 5550 Game Rooms (ccpc2015 K)(dp)
    HDU 5542 The Battle of Chibi (ccpc 南阳 C)(DP 树状数组 离散化)
    HDU 5543 Pick The Sticks (01背包)
    HDU 5546 Ancient Go (ccpc2015南阳G)
    NB-IoT的DRX、eDRX、PSM三个模式 (转载,描述的简单易懂)
    MQTT 嵌入式端通讯协议解析(转)
  • 原文地址:https://www.cnblogs.com/0803yijia/p/2620689.html
Copyright © 2011-2022 走看看