hdu 2647 Reward

拓扑排序入门题,可以用STL来做,这份代码中没有用

对于给出的图判断是否为有向无环图(dag),若不是,输出-1

其实是按层来处理拓扑序列,算法是先找出入度为0的点,然后删除所有以这些顶点为弧尾的弧,使弧头的入度减1,然后再看下一轮的顶点中那些顶点入度为0,然后依此类推,直到所有点的入度都为0,如果最后结束的时候所有点入度为0,那么是一个dag,否则不是,输出-1,这个过程可以用队列来实现,这个代码里面没有这样做,而是每一层都重新扫描一遍,找出入度为0的顶点(之前已经纳入拓扑序列的顶点就用vis[i]=1来标记),应该用队列实现的话时间会更好

另外其中是要构建邻接表的,用数组来构建,当然可以直接用STL的vector来实现,队列也可以用STL的queue来实现,这份代码中都没有这样做

另外注意一点,输入中a b  有向边是b->a , 不要搞反了 

 

#include <stdio.h>

#include <string.h>

#define MAXN 10010

#define MAXM 20010

int n,m;

int first[MAXN],in[MAXN];

int u[MAXM],v[MAXM],next[MAXM];

bool vis[MAXN];



void input()

{

    int i,a,b,f;

    memset(first,-1,sizeof(first));

    memset(in,0,sizeof(in));

    for(f=1,i=0; i<m; i++)

    {

        scanf("%d%d",&a,&b);

        u[i]=b; v[i]=a;

        in[v[i]]++;

        next[i]=first[u[i]];

        first[u[i]]=i;

    }

}



int topsort()

{

    int sum;

    int temp[MAXN];

    int i,j,k,c,t;

    memset(vis,0,sizeof(vis));

c=0;  sum=0; j=0;  

//j表示的是层数,第一层是0,所以工资为888,依次是889.890

//c表示已经有多少个点纳入拓扑序列,c=n则是dag

//sum是最后的答案

while(1)

    {

        k=0;

        for(i=1; i<=n; i++)  //对应n个顶点

            if(!vis[i] && in[i]==0)

            {

                vis[i]=1;  c++;  sum+=(888+j);

                temp[k++]=i;  //记录下当前这一轮找到的入度为0的顶点

            }

        if(c>=n)  return sum;

        if(!k)    return -1; 

    //如果在这次构建结束后,扫描所有顶点都找不到入度为0那说明存在环

        for(i=0; i<k; i++)  

//对应temp数组,这一轮找到的入度为0的顶点,要遍历它的邻接表,使对应的弧头入度减1

        {

            t=temp[i];  //记录弧尾顶点标号

            t=first[t];  //记录这个顶点的第一条弧的编号

            while(t!=-1)  

            {

                in[v[t]]--;

                t=next[t];

            }

        }



        j++;

    }

}



int main()

{

    int ans;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        input();

        printf("%d\n",ans=topsort());

    }

    return 0;

}

你可能感兴趣的:(HDU)