HDU 1285 确定比赛名次 + HDU 4857 逃生(拓扑排序由浅入深)

学拓扑排序还是想补题,先从水题入手,学到了一个最简单的拓扑排序,时间复杂度高达O(n ^ 3),也就水水题还行

比赛那道题要是这么做就MLE,要不然也得TLE哈哈哈

HDU - 1285

其实虽然方法水,和所有拓扑排序原理还是一样的,就是建图然后逐条删边,边删边输出

原理这里讲的很清楚了:拓扑排序

直接挂很水很水的代码,好的方法肯定要学,慢慢来。。。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
bool vis[505][505];
int indegree[505];
void topo()
{
    bool flag = 0;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
    {
        if(! indegree[j])
        {
            indegree[j] --; //防止重复判断
            if(flag)printf(" ");
            printf("%d",j);
            flag = 1;
            for(int k = 1; k <= n; k ++)
                if(vis[j][k])
                indegree[k] --;
            break;//及时跳出进入i + 1层循环
        }
    }
}
int main()
{
    while(scanf("%d %d", &n, &m) != EOF)
    {
        memset(vis, 0, sizeof(vis));
        memset(indegree, 0, sizeof(indegree));
        int a, b;
        for(int i = 1; i <= m; i ++)
        {
            scanf("%d %d", &a, &b);
            if(! vis[a][b])
            {
                vis[a][b] = 1;
                indegree[b] ++;
            }
        }
        topo();
        printf("\n");
    }
    return 0;
}

然后是优先队列写法,这个时间复杂度低多了

注意priority_queue<int,vector<int>,greater<int> >,是优先队列元素从小到大排列,将greater改成less就变为从大到小
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
int ind[505];
bool vis[505][505];
int to[505];
int cnt;
void topo()
{
    priority_queue<int, vector<int>, greater<int> >q;
    for(int i = 1; i <= n; i ++)
    {
        if(! ind[i])
            q.push(i);
    }
    while(! q.empty())
    {
        int h = q.top();
        q.pop();
        to[cnt ++] = h;
        for(int i = 1; i <= n; i ++)
        {
            if(vis[h][i])
            {
                ind[i] --;
                if(! ind[i])q.push(i);
                vis[h][i] = 0;
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m) != EOF)
    {
        memset(vis, 0, sizeof(vis));
        memset(ind, 0, sizeof(ind));
        int a, b;
        for(int i = 1; i <= m; i ++)
        {
            scanf("%d%d",&a,&b);
            if(! vis[a][b])
            {
                vis[a][b] = 1;
                ind[b] ++;
            }
        }
        cnt = 0;
        topo();
        int flag = 0;
        for(int i = 0; i < cnt; i ++)
        {
            if(flag)printf(" ");
            printf("%d",to[i]);
            flag = 1;
        }
        printf("\n");
    }
    return 0;
}

如果这道题的数据和比赛的时候一样大,怎么办,开一个50000*50000的数组肯定爆了,用vector很好的解决了这个问题,并且这种方法不用去重,原因也很简单,自己领会

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
int ind[505];
int to[505];
int cnt;
int main()
{
    while(scanf("%d%d",&n,&m) != EOF)
    {
        vector<int>e[505];
        memset(ind, 0, sizeof(ind));
        int a, b;
        for(int i = 1; i <= m; i ++)
        {
            scanf("%d%d",&a,&b);
            e[a].push_back(b);
            ind[b] ++;
        }
        cnt = 0;

        priority_queue<int, vector<int>, greater<int> >q;
        for(int i = 1; i <= n; i ++)
        {
            if(! ind[i])
                q.push(i);
        }
        while(! q.empty())
        {
            int h = q.top();
            to[cnt ++] = h;
            q.pop();
            for(int i = 0; i < e[h].size(); i ++)
            {
                int H = e[h][i];
                ind[H] --;
                if(! ind[H])q.push(H);
            }
        }

        int flag = 0;
        for(int i = 0; i < cnt; i ++)
        {
            if(flag)printf(" ");
            printf("%d",to[i]);
            flag = 1;
        }
        printf("\n");
    }
    return 0;
}

然后这道题到此为止,做比赛题,然而然而然而然而一直wa,怎么改也不对,后来得知忽略了一个条件,那就是答案只有一个合理的存在,因为这道题的输出是有前提的,后来知道这个叫反向拓扑排序? 

拓扑排序 这个博客讲的很详细,感觉自己还完全没有学会拓扑排序啊,哎哎继续刷题
AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
int ind[50005];
int to[50005];
int cnt;
int main()
{
    int t;
    scanf("%d",&t);
    while(t --)
    {
        scanf("%d%d",&n,&m);
        vector<int>e[50005];
        memset(ind, 0, sizeof(ind));
        int a, b;
        for(int i = 1; i <= m; i ++)
        {
            scanf("%d%d",&a,&b);
            e[b].push_back(a);
            ind[a] ++;
        }
        cnt = n;
        priority_queue<int, vector<int>, less<int> >q;
        for(int i = 1; i <= n; i ++)
        {
            if(! ind[i])
                q.push(i);
        }
        while(! q.empty())
        {
            int h = q.top();
            to[cnt --] = h;
            q.pop();
            for(int i = 0; i < e[h].size(); i ++)
            {
                int H = e[h][i];
                ind[H] --;
                if(! ind[H])q.push(H);
            }
        }

        int flag = 0;
        for(int i = 1; i <= n; i ++)
        {
            if(flag)printf(" ");
            printf("%d",to[i]);
            flag = 1;
        }
        printf("\n");
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值