POJ 3687 逆序拓扑

额。题目大意:有N个球。编号和重量都是唯一不重复的。然后。给你m个pair a和b,表示编号为a的点一定比编号为b的点轻。然后捏、输出每个点对应的重量。关键是要求。如果有多种可能性的话,输出让序号小的点重量也尽量小的ans....而且先满足1号。再二号。and so on....那么问题来了。如果我们按照编号从小到大开始拓扑、然后每次对编号小的球赋给当前最小重量的话。T_T。貌似无法保证所有的球从小到大开始编号小则重量尽量小、比如说、第一次 入度为0得点有3 4 5 那么赋给了3重量1.第二次入度为0的点有2 4 5.那么。只能赋给2重量2了。如果再下次是4  5的话、赋给4 号球 重量3、再下次是1 5.赋给1号球重量4.但实际上这说明4——>1、而3 4 5 是并列关系。那就是先满足4的话就可以让1号球最小喽。恩。。是这样滴、、、

代码也灰常简单。就是按照入度为0的点的顺序来。貌似这就是拓扑排序。。2333333333333好吧。。我是很无知地。。。以为拓扑排序一定会用到邻接表形式。加一条边的insert函数。、T_T

附代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#define maxn 210
#define maxm 41000
using namespace std;

int digree[maxn];
int map[maxn][maxn];
int ans[maxn];
int vis[maxn];
int n, m;

void init()
{
    memset(digree, 0, sizeof(digree));
    memset(map, 0, sizeof(map));
    memset(vis, 0, sizeof(vis));
}

void topsort()
{
     for (int i=n; i>=1; --i)
     {
         int k = -1;
         for (int j=n-1; j>=0; --j)
         {
             if (!vis[j] && digree[j] == 0)
             {
                 k = j;
                 break;
             }
         }
         if (k == -1)
         {
             cout << "-1\n";
             return;
         }
         vis[k] = 1;
         ans[k] = i;
         for (int j=0; j<n; ++j)
         {
             if (map[k][j])
             digree[j]--;
         }
     }
     cout << ans[0];
     for (int i=1; i<n; ++i)
     {
        cout << ‘ ‘ << ans[i];
     }
     cout << endl;
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n >> m;
        init();
        for (int i=0; i<m; ++i)
        {
            int a, b;
            cin >> a >> b;
            a--; b--;
            if (!map[b][a])
            {
               map[b][a] = 1;
               digree[a]++;
            }
        }
        topsort();
    }
    return 0;
}

时间: 2024-08-08 13:51:38

POJ 3687 逆序拓扑的相关文章

[ACM] POJ 3687 Labeling Balls (拓扑排序,逆向建边)

Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10161   Accepted: 2810 Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 to N in such a way that: No two balls share

POJ 3687-Labeling Balls(逆序拓扑排序)

Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11256   Accepted: 3230 Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 to N in such a way that: No two balls share

[ACM] POJ 3687 Labeling Balls (拓扑排序,反向生成端)

Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10161   Accepted: 2810 Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 toN in such a way that: No two balls share

POJ - 3687 Labeling Balls (拓扑排序)

题意:N个点,给出M条两个点u.v,满足u比值小.给这N个点编号,要求排在前的比排在后的质量小,且编号不重复.求每点能得到最小编号的编号方法. 分析:用拓扑排序求解. 用优先队列来存待标记的点,编号大的点优先出队列,然后从大到小依次标记(编号小的优先肯定是错的,当时wa死了). 若求不出拓扑排序则答案无解. #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #i

POJ 2299 Ultra-QuickSort(归并排序求逆序对数)

题目地址:POJ 2299 今天下午的多校看来没有白做...实在做不出题闲着无聊看小白鼠学会了个归并排序.哈哈. 归并排序简单地说其实就是先分成一个二叉树直至单个,然后依次从最底层不断进行合并,逆序对数就是在合并的过程中,加入后面的那段中到了比他大的时候,那后面的那些就都是比他大的,都是逆序对数,所以直接加上即可.网上资料很多,就不细说了..用了分治的思想. 自己根据理解写的代码,考虑的太不全面了..又调了好长时间... 代码如下: #include <algorithm> #include

POJ 1840 Brainman(逆序对数)

题目链接:http://poj.org/problem?id=1804 题意:给定一个序列a[],每次只允许交换相邻两个数,最少要交换多少次才能把它变成非递降序列. 思路:题目就是要求逆序对数,我们知道,求逆序对最典型的方法就是树状数组,但是还有一种方法就是Merge_sort(),即归并排序.实际上归并排序的交换次数就是这个数组的逆序对个数,归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来.在合并的过程中(设l<=i<=mid

POJ 2299 Ultra-QuickSort (求序列的逆序对数)

题意:废话了一大堆就是要你去求一个序列冒泡排序所需的交换的次数. 思路:实际上是要你去求一个序列的逆序队数 看案例: 9 1 0 5 4 9后面比它小的的数有4个 1后面有1个 0后面没有 5后面1个 4后面没有 所以结果为4+1+0+1+0=6 所以逆序对的定义如果不清楚可以自己总结了 这道题说白了就是要你用归并排序求逆序对数. 下面是搜到某牛给的逆序对数的方法: 假设回溯到某一步,后面的两部分已经排好序(就是说当前需要归并的两个部分都是分别有序的),假设这两个序列为 序列a1:2 3 5 9

hdu 4857 逃生(拓扑排序逆序 + 优先队列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857 题意:有编号 1 - n 的 n 个人逃生,编号越小的人越有钱, 在满足 m 个前提的条件下要尽可能早的逃脱 .m个前提,对于每个前提 a , b,代表 a 要早于 b逃脱. 思路: (1)这题可以理解为有钱的人优先级越高,所以可以用优先队列. (2)但是要注意这道题和字典序升序的区别. eg:5 1 5 1 按照字典序的答案:2 3 4 5 1,    本题答案: 5 1 2 3 4. 因为

POJ 2299 Ultra-QuickSort (树状数组or 归并排序分治求逆序对数)

题目大意就是说帮你给一些(n个)乱序的数,让你求冒泡排序需要交换数的次数(n<=500000) 显然不能直接模拟冒泡排序,其实交换的次数就是序列的逆序对数. 由于数据范围是 0 ≤ a[i] ≤ 999,999,999所以先要离散化,然后用合适的数据结果求出逆序 可以用线段树一步一步添加a[i],每添加前查询前面添加比它的大的有多少个就可以了. 也可用树状数组,由于树状数组求的是(1...x)的数量和所以每次添加前查询i-sum(a[i])即可 树状数组: //5620K 688MS #incl