HDOJ 2647 Reward (拓扑排序)

本文探讨了拓扑排序的原理及应用,通过实例展示了如何利用拓扑排序解决实际问题,包括工资分配、图的转置等。文章详细解释了分层排序的方法,以及在排序过程中遇到环时的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

超级传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2647


本题是一个典型的拓扑排序,但是在排序的过程中需要对结点进行分层。拓扑排序采用消去零入度结点法,分层的时候需要注意:当消去一个结点时,其子结点是属于下一层的,应当用数组is_next[]进行标记,防止分层混乱(此处贡献多个WA)。另外,为了方便计算结果,图最好转置建立,即把a->b换成b->a,这样的话第一层的结点员工都是基本工资888,然后第n层的工资数就是888+n-1,再乘以每层的员工数目,即可得到最少需要支付的金额。如果拓扑排序完成后最后仍有剩余结点未消去,则说明剩余结点构成环,题目无解,输出“-1”。

代码如下:


#include<stdio.h>
#include<string.h>
#define N 10005
#define M 20005
int n,m;
int w[N][20],num[N],r[N],vis[N],div[N],d_num,is_next[N];
int main () {
    int i,j,k,h,a,b,ans,cur,ok;
    while (scanf("%d%d",&n,&m) != EOF) {
        memset(num,0,sizeof(num));
        memset(vis,0,sizeof(vis));
        memset(r,0,sizeof(r));
        memset(div,0,sizeof(div));
        for (i=1;i<=m;i++) {
            scanf("%d%d",&a,&b);
            w[b][++num[b]] = a;
            r[a] ++;
        }
        d_num = 0;
        for (k=1;k<=n;k++) {
            ++d_num;
            memset(is_next,0,sizeof(is_next));
            for (i=1;i<=n;i++) {
                if (!r[i] && !vis[i] && !is_next[i]) {
                    ok = 1;
                    for (j=1;j<=num[i];j++) {
                        r[w[i][j]] --;
                        if (r[w[i][j]]<0) r[w[i][j]] = 0;
                        is_next[w[i][j]] = 1;
                    }
                    vis[i] = 1;
                    div[d_num]++;
                }
            }
        }
        ok = 1;
        cur = 888;
        ans = 0;
        for (i=1;i<=n;i++) {
            if (!vis[i]) {
                ok = 0;
                break;
            }
        }
        if (ok) {
            for (i=1;i<=d_num;i++) {
                if (div[i]) {
                    ans += div[i]*cur++;
                }
            }
            printf("%d\n",ans);
        } else printf("-1\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值