HDU 4857 逃生(反向建边的拓扑排序+贪心思想)

逃生

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7736    Accepted Submission(s): 2248


Problem Description
糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。

现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。

负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。

那么你就要安排大家的顺序。我们保证一定有解。
 
Input
第一行一个整数T(1 <= T <= 5),表示测试数据的个数。
然后对于每个测试数据,第一行有两个整数n(1 <= n <= 30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。

然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。
 
Output
对每个测试数据,输出一行排队的顺序,用空格隔开。
 
Sample Input
1 5 10 3 5 1 4 2 5 1 2 3 4 1 4 2 3 1 5 3 5 1 2
 
Sample Output
1 2 3 4 5
 
Author
CLJ
 
Source
 
Recommend
We have carefully selected several similar problems for you:  6447 6446 6445 6444 6443 
 
分析:
n个元素,m组约束条件,猜测拓扑排序可以解决
约束条件a b表示a必须在b之前
题目给的要求是数字小的尽可能的排前面
根据贪心的思想,越前面的越重要,所以我们先将数字大的不重要的放后面,
这样一直往前放,最后放的才是数字小的(在满足约束的条件下,拓扑的作用就是要保证满足约束)
所以我们反向建边,每次选择数字较大的,从后面开始往前面放
这样一开始放的就是最不重要的位置(最后)
最后放的则是最前面的位置(第一个)
当然,这一切的放置都是在满足约束条件的前提下进行的
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string.h>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};

int getval()
{
    int ret(0);
    char c;
    while((c=getchar())==' '||c=='
'||c=='
');
    ret=c-'0';
    while((c=getchar())!=' '&&c!='
'&&c!='
')
        ret=ret*10+c-'0';
    return ret;
}

#define max_v 30005
int indgree[max_v];
vector<int> vv[max_v];
priority_queue<int,vector<int>,less<int> > q;
int n,m;
int a[max_v];
void tpsort()
{
    for(int i=1; i<=n; i++)
    {
        if(indgree[i]==0)
            q.push(i);
    }
    int temp;
    int cnt=0;
    int k=n;
    while(!q.empty())
    {
        temp=q.top();
        q.pop();
        a[k--]=temp;
        cnt++;
        for(int i=0; i<vv[temp].size(); i++)
        {
            indgree[vv[temp][i]]--;
            if(indgree[vv[temp][i]]==0)
                q.push(vv[temp][i]);
        }
    }
}
int main()
{
    int t;
    int x,y;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);

        memset(indgree,0,sizeof(indgree));
        for(int i=1; i<=n; i++)
            vv[i].clear();
        while(!q.empty())
            q.pop();

        for(int i=1; i<=m; i++)
        {
            scanf("%d %d",&y,&x);


            if(count(vv[x].begin(),vv[x].end(),y)==0)
            {
                vv[x].push_back(y);
                indgree[y]++;
            }

        }
        tpsort();
        for(int i=1; i<=n; i++)
        {
            if(i==1)
                printf("%d",a[i]);
            else
                printf(" %d",a[i]);
        }
        printf("
");
    }
    return 0;
}
/*
分析:
n个元素,m组约束条件,猜测拓扑排序可以解决

约束条件a b表示a必须在b之前

题目给的要求是数字小的尽可能的排前面

根据贪心的思想,越前面的越重要,所以我们先将数字大的不重要的放后面,

这样一直往前放,最后放的才是数字小的(在满足约束的条件下,拓扑的作用就是要保证满足约束)

所以我们反向建边,每次选择数字较大的,从后面开始往前面放

这样一开始放的就是最不重要的位置(最后)

最后放的则是最前面的位置(第一个)

当然,这一切的放置都是在满足约束条件的前提下进行的
*/
原文地址:https://www.cnblogs.com/yinbiao/p/9852257.html