码迷,mamicode.com
首页 > 编程语言 > 详细

hdu 5154 拓扑排序

时间:2018-04-15 12:04:18      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:技术分享   tin   empty   node   for   现在   记录   ack   接下来   

例题:hdu 5154  链接  http://acm.hdu.edu.cn/showproblem.php?pid=5154

题目意思是第一行先给出n和m表示有n件事,m个关系,接下来输入m行,每行有a,b两个数,他们之间的关系就是第a件事要在

第b件事之前做完,然后问你可不可以在符合这m个关系的情况下把这n件事情做完,可以就输出YES,否则输出NO。

现在先假设a b之间的关系用a指向b来表示,即a-->b。

题目里给的两个样例有点简单,来个稍微复杂一点的好吧。

技术分享图片

第一次搞这个,不太会,见谅。看上面这个图,然后我们可以先得到这些数据:

6 7

1 5

1 3

2 5

3 4

3 5

3 6

5 6

入度:就理解为一个点被箭头指的次数(作为终点的次数),上图中 点1的入度为0,点5的入度为3,点3的入度为1。

出度:反一下,箭头出去的次数(作为起点的次数),点1的出度为2,点5的为1。(出度在这题用不到)

我们程序就是先找到入度为0(一开始有点1和点2)的点,然后把这个点标记为走过,再把以这个点为起点的边删掉,

我们先选点1,然后就下面酱紫了。

 

技术分享图片

然后入度为0的点就有点2和点3了,随便选择一个,假设3好吧,然后:技术分享图片

 

一直这样下去技术分享图片

技术分享图片

技术分享图片

然后就没有然后了,把点4删了就完了。

以上是符合条件输出YES的情况,假设图是这样的

技术分享图片

 那么1和3就构成了一个环,入度为0的点只有2,然后删去2和以2位起点的边:

技术分享图片
然后就没有入度为0的边了,然后程序结束,可是所有的点还没有走完(没有做完所有的事情),输出NO。

接下来就是怎么写的问题了。看代码吧

用vector的:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
vector<int>v[105];
int n,m,k,t;
int num[105],vis[105];//num数组记录入度数目,vis数组看这个点是否访问过 
void init()
{
    for(int i=1;i<=n;i++)
    v[i].clear();
    memset(num,0,sizeof(num));
    memset(vis,0,sizeof(vis));        
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            num[b]++; //点b入度 +1 
            v[a].push_back(b);//a-->b 
        }
        int flag=0;
        for(int i=1;i<=n;i++)//最多n次循环 
        {
            for(int j=1;j<=n;j++)//找1到n入度为0的点 
            {
                if(vis[j])
                continue;
                if(num[j]==0)
                {
                    vis[j]=1;//标记这个点走过 
                    for(int k=0;k<v[j].size();k++)
                    {
                        if(num[v[j][k]])
                        num[v[j][k]]--;//删边 
                    }
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(!vis[i])//看是不是所有事都做完了 
            flag=1;
        }
        if(flag)
        printf("NO\n");
        else
        printf("YES\n");
    }
    return 0;
 } 

再用队列和链式前向星优化一下:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
int n,m,k,t;
struct node{
    int v,next;
}str[10005];
int head[105],vis[105],in[105],cnt;
queue<int>q;
void add(int u,int v)
{
    str[++cnt].v=v;
    str[cnt].next=head[u];
    head[u]=cnt;
}
void init()
{
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    cnt=0;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
            in[b]++;
        }
        while(!q.empty())
        q.pop();
        for(int i=1;i<=n;i++)
        {
            if(!in[i])
            q.push(i);
        }
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            vis[u]=1;
            for(int i=head[u];i!=-1;i=str[i].next)
            {
                int v=str[i].v;
                if(in[v])
                in[v]--;
                if(in[v]==0&&!vis[v])
                q.push(v);
            }
        }
        int flag=1;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i])
            {
                flag=0;
                break;
            }
        }
        if(flag)
        printf("YES\n");
        else
        printf("NO\n");
    }
    return 0;
}

 

hdu 5154 拓扑排序

标签:技术分享   tin   empty   node   for   现在   记录   ack   接下来   

原文地址:https://www.cnblogs.com/6262369sss/p/8836250.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!