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 }
  • 相关阅读:
    DSAPI+DS控件库 Windows7风格控件演示
    DSAPI 键盘鼠标钩子
    DSAPI WIN7磨砂+窗体投影组合
    DSAPI 字符串和文件转Md5字符串
    DS控件库 DS标签的另类用法之折叠展开
    DSAPI 网卡流量监控
    DS控件库 Win7链接列表框效果1:右侧箭头
    DS控件库 DSLed控件呈现滚动字幕效果
    DS控件库 DS按钮多种样式
    DSAPI 简单WebAPI实现
  • 原文地址:https://www.cnblogs.com/0803yijia/p/2620689.html
Copyright © 2011-2022 走看看