zoukankan      html  css  js  c++  java
  • 【vijos】1790 拓扑编号(拓扑+贪心)

    https://vijos.org/p/1790

    好神的贪心题。。

    一开始我也想到了贪心,但是是错的。。sad

    就是因为每一个节点的编号与逆图的子树有关,且编号一定是>=子树的儿子+1的。但是想了想很快发现不可做。。因为这种dfs牵扯到的东西太多了。

    然后我想到这些约束是不是和差分约束有关,然后就脑补,可是后边发现这也是不可做的,因为差分约束算出来的不是编号。sad。。

    无奈看题解。

    sad

    这个和我第一个想法有关。。。

    因为编号一定是>=逆图的子树儿子+1,显然如果每一次将编号从大向小的放是满足这一性质的。

    建一个逆的图,那么就是每次取最大的标号度为0的点,那么这个点的编号就是当前剩余的编号。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
    #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '	'; cout << endl
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    priority_queue<int> id;
    const int N=100005, M=200005;
    int ihead[N], cnt, n, m, tot, in[N], a[N];
    struct ED { int to, next; }e[M];
    void add(int u, int v) {
    	e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v;
    }
    
    int main() {
    	read(n); read(m); tot=n+1;
    	rep(i, m) {
    		int u=getint(), v=getint();
    		add(v, u); ++in[u];
    	}
    	for1(i, 1, n) if(in[i]==0) id.push(i);
    	while(!id.empty()) {
    		int u=id.top(); id.pop();
    		a[u]=--tot;
    		for(int i=ihead[u]; i; i=e[i].next) {
    			--in[e[i].to];
    			if(in[e[i].to]==0) id.push(e[i].to);
    		}
    	}
    	for1(i, 1, n) printf("%d ", a[i]);
    	return 0;
    }
    

    描述

    H国有n个城市,城市与城市之间有m条单向道路,满足任何城市不能通过某条路径回到自己。

    现在国王想给城市重新编号,令第i个城市的新的编号为a[i],满足所有城市的新的编号都互不相同,并且编号为[1,n]之间的整数。国王认为一个编号方案是优美的当且仅当对于任意的两个城市i,j,如果i能够到达j,那么a[i]应当<a[j]。

    优美的编号方案有很多种,国王希望使1号城市的编号尽可能小,在此前提下,使得2号城市的编号尽可能小...依此类推。

    格式

    输入格式

    第一行读入n,m,表示n个城市,m条有向路径。

    接下来读入m行,每行两个整数:x,y
    表示第x个城市到第y个城市有一条有向路径。

    输出格式

    输出一行:n个整数
    第i个整数表示第i个城市的新编号a[i],输出应保证是一个关于1到n的排列。

    样例1

    样例输入1[复制]

    5 4
    4 1
    1 3
    5 3
    2 5

    样例输出1[复制]

    2 3 5 1 4

    限制

    每个测试点1s

    提示

    30%的测试点满足:n <= 10, m <= 10
    70%的测试点满足:n <= 1000, m <= 10000
    100%的测试点满足:n <= 100000, m <= 200000
    输入数据可能有重边,可能不连通,但保证是有向无环图。

    来源

    Topcoder

  • 相关阅读:
    Java Thread(一) Outline
    Gradle学习(四) web工程构建
    Gradle学习(三) 依赖管理基础
    Gradle学习(二) Java Plugin
    Gradle学习(一)
    二维码zxing源码分析(五)精简代码
    二维码zxing源码分析(四)wifi部分
    二维码扫描 zxing源码分析(三)result、history部分
    二维码zxing源码分析(二)decode部分
    二维码zxing源码分析(一)camera部分
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4010388.html
Copyright © 2011-2022 走看看