SCU 4110 / POJ 3687 反向拓扑排序 + 优先队列

题目链接:

SCU 4110

POJ 3687


分析:拓扑排序,注意根据题的要求,要先保证1号球最轻,如果我们由轻的向重的连边,然后我们依次有小到大每次把重量分给一个入度为0的点,那么在拓扑时我们面对多个入度为0的点,我们不知道该把最轻的分给谁才能以最快的速度找到1号(使1号入度为0),并把当前最轻的分给1号。所以我们要由重的向轻的连边,然后从大到小每次把一个重量分给一个入度为0的点。这样我们就不用急于探求最小号。我们只需要一直给最大号附最大值,尽量不给小号赋值,这样自然而然就会把轻的重量留给小号。


分析转自:http://www.cnblogs.com/rainydays/archive/2011/07/20/2112047.html


代码如下:

// SCU 4110
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
using namespace std;

// -- 宏定义们 –-
#define fi first
#define se second
#define isf(n) int n; scanf("%d", &n)
#define sf(n) scanf("%d", &n)
#define sflf(n) scanf("%lf", &n)
#define sfs(s) scanf("%s", s)
#define sf2(n, m) scanf("%d%d", &n, &m)
#define sf3(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define sf3lf(a, b, c) scanf("%lf%lf%lf", &a, &b, &c)
#define sf4(a, b, c, d) scanf("%d%d%d%d", &a, &b, &c, &d)
#define sf4lf(a, b, c, d) scanf("%lf%lf%lf%lf", &a, &b, &c, &d)
#define sfi64d(n) scanf("%I64d", &n)
#define sflld(n) scanf("%lld", &n)
#define pf(n) printf("%d\n", n)
#define pfs(s) printf("%s\n", s)
#define pfi64d(n) printf("%I64d\n", n)
#define pflld(n) printf("%lld\n", n)
#define ilen(s) int len = strlen(s)
#define len(s) len = strlen(s)
#define clr(a, x) memset(a, (x), sizeof(a))
#define rep(i, n) for(int i = 0; i < (n); ++i)
#define repx(i, x, n) for(int i = (x); i < (n); ++i)
#define repv(i, x, n) for(int i = (x); i >= (n); --i)
#define eps 1e-8
typedef long long ll;
typedef pair<int, int> pii;
typedef priority_queue<int, vector<int>, greater<int> > pq_gi;
typedef priority_queue<int, vector<int>, less<int> > pq_li;
// ----------

const int N = 222;
bool dij[N][N], qvis[N];
int in[N], ans[N];
pq_li q;

int main()
{
    // freopen("in", "r", stdin);
    isf(t);
    int n, m, a, b, out;
    while(t--) {
        while(!q.empty()) q.pop();
        clr(dij, 0); clr(in, 0); clr(ans, 0); clr(qvis, 0);

        sf2(n, m);
        rep(i, m) {
            sf2(a, b);
            if(!dij[b][a]) in[a]++;
            dij[b][a] = 1;
        }

        repx(i, 1, n + 1) {
            if(!in[i]) { q.push(i); qvis[i] = 1; }
        }

        int vn = n;
        while(!q.empty()) {
            out = q.top();
            q.pop();
            ans[out] = vn--;
            repx(i, 1, n + 1) {
                if(dij[out][i] && !qvis[i] && (--in[i]) == 0) {
                    q.push(i);
                    qvis[i] = 1;
                }
            }
        }
        if(vn) pf(-1);
        else {
            repx(i, 1, n + 1) {
                printf("%s%d", i == 1 ? "" : " ", ans[i]);
            }
            puts("");
        }
        puts("");
        
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值