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;
}
posted @ 2012-10-17 18:45  Titanium  阅读(899)  评论(0编辑  收藏  举报