Vijos1790:拓扑编号

描述

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的排列。

输入:

5 4
4 1
1 3
5 3
2 5

输出:

2 3 5 1 4

思路:按反向边构图,拓扑排序时取出序号最大的结点,赋予当前最大编号。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=100005;
struct Edge{
    int to,next;
};
Edge es[200005];
int head[MAXN],tot;
int n,m;
int id[MAXN],deg[MAXN];
void addedge(int u,int v)
{
    es[tot].to=v;
    es[tot].next=head[u];
    head[u]=tot++;
}
void topsort()
{
    int cnt=n;
    priority_queue<int> que;
    for(int i=1;i<=n;i++)
        if(deg[i]==0)
        {
            que.push(i);
        }
    while(!que.empty())
    {
        int now=que.top();que.pop();
        id[now]=cnt--;
        for(int i=head[now];i!=-1;i=es[i].next)
        {
            int u=es[i].to;
            deg[u]--;
            if(deg[u]==0)
            {
                que.push(u);
            }
        }
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(v,u);
        deg[u]++;
    }
    topsort();
    for(int i=1;i<=n;i++)
    {
        printf("%d%c",id[i],i==n?‘\n‘:‘ ‘);
    }
    return 0;
}    
时间: 2024-08-04 14:36:27

Vijos1790:拓扑编号的相关文章

拓扑编号 vijos1790

题意就是拓扑排序,要求1的序号尽可能小,然后2的序号尽可能小,3,4... 一开始很容易想到直接贪心,每次选一个入度为0的点,如果有多个,就选编号最小的那个,但是很容易找到反例. 看了下题解,应该是反着做拓扑排序,每次取编号最大的,但是没有人给出证明.下面给出我的证明,欢迎指出错误. ps:参考了一位大牛的文章,poj有一道题类似,参考了他的题解,但是找不到了,所以没法放出他的链接了,先道歉. 假设我们按逆拓扑排序的方法求出了一个拓扑序列(把得到的反序列正过来),记为A. 假设最优解的拓扑序列是

vijos 拓扑编号

描述 H国有n个城市,城市与城市之间有m条单向道路,满足任何城市不能通过某条路径回到自己. 现在国王想给城市重新编号,令第i个城市的新的编号为a[i],满足所有城市的新的编号都互不相同,并且编号为[1,n]之间的整数.国王认为一个编号方案是优美的当且仅当对于任意的两个城市i,j,如果i能够到达j,那么a[i]应当<a[j]. 优美的编号方案有很多种,国王希望使1号城市的编号尽可能小,在此前提下,使得2号城市的编号尽可能小...依此类推. 格式 输入格式 第一行读入n,m,表示n个城市,m条有向路

【vijos】1790 拓扑编号(拓扑+贪心)

https://vijos.org/p/1790 好神的贪心题.. 一开始我也想到了贪心,但是是错的..sad 就是因为每一个节点的编号与逆图的子树有关,且编号一定是>=子树的儿子+1的.但是想了想很快发现不可做..因为这种dfs牵扯到的东西太多了. 然后我想到这些约束是不是和差分约束有关,然后就脑补,可是后边发现这也是不可做的,因为差分约束算出来的不是编号.sad.. 无奈看题解. sad 这个和我第一个想法有关... 因为编号一定是>=逆图的子树儿子+1,显然如果每一次将编号从大向小的放是

拓扑编号

#include<cstdio>//https://vijos.org/p/1790 #include<iostream>#include<vector>#include<queue>using namespace std;const int MAXN=500;int n,m;vector<int>map[MAXN];int rudu[MAXN];int b[MAXN][MAXN];int q[MAXN],tail=-1,head=-1;int

图论算法 有图有代码 万字总结 向前辈致敬

图的定义 背景知识 看到这篇博客相信一开始映入读者眼帘的就是下面这幅图了,这就是传说中的七桥问题(哥尼斯堡桥问题).在哥尼斯堡,普雷格尔河环绕着奈佛夫岛(图中的A岛).这条河将陆地分成了下面4个区域,该处还有着7座连接这些陆地的桥梁. 问题是如何从某地出发,依次沿着各个桥,必须经过每座桥且每座桥只能经过1次,最终回到原地. 不知道这个问题且好奇的童鞋现在肯定在忙活着找出来这道题的结果了. 是伟大的数学家欧拉(Leonhard Euler)在1736年首次使用图的方法解决了该问题. 欧拉将上面的模

山西胡策 #7

A. B. C. 题意:给出(i, j)之类的约束表示要j必须先i,问1尽量靠前.2尽量靠前.3尽量靠前以此类推的最优方案,或输出无解. #include <bits/stdc++.h> using namespace std; const int N=100005; int cnt, ihead[N], in[N], ans[N], tot, n, m; struct E { int next, to; }e[N]; void add(int x, int y) { e[++cnt]=(E)

10月刷题总结

(写的题真少QAQ 动态规划: [vijos]1286 座位安排(状压dp) [BZOJ]1026: [SCOI2009]windy数(数位dp) [BZOJ]1596: [Usaco2008 Jan]电话网络(树形dp+特殊的技巧) [BZOJ]1827: [Usaco2010 Mar]gather 奶牛大集会(树形dp) [BZOJ]2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛(树形dp) 计数: [vijos]1789 String(组合计数+奇怪的题)

寒假集训日志(二)——最小生成树,拓扑排序,欧拉回路,连通路

今天学的内容挺多的. (一)首先说最小生成树,两种算法: 1.Kruskal算法( 将边排序,然后再选,关键在于检查是否连通,使用并查集) 2.Prim算法(使用点集,有点类似与最短路的算法) 第一题是并查集算法的使用: A - The Suspects Time Limit:1000MS     Memory Limit:20000KB     64bit IO Format:%I64d & %I64u Submit Status Description 严重急性呼吸系统综合症( SARS),

HDU 6165-强连通分量+拓扑

题意 给出一幅有向图,判定是否存在一对顶点互相不可达. 分析 在一个强连通分量里的点对是互相可达的,我们先求出强连通分量再缩点构建新图 然后我们对新图进行拓扑排序,当开始时或者删完一个点及它的关联边时,若入度为0的点多于1个,则这些点互相不可达 代码 #include <map> #include <set> #include <queue> #include <cmath> #include <ctime> #include <vecto