您的位置:首页 > 其它

hdu 1285 确定比赛名次

2012-10-16 23:48 330 查看
//拓扑排序裸题,题目要求按编号从小到大输出,要换一种思维去思考

//按照数据结构课本的算法,建立邻接表,用栈实现。初始化先将入度为0的顶点入栈,然后以栈顶顶点为准,先将栈顶顶点出栈输出它的信息,然后扫描它的邻接表,没找到一个弧头就将其入度减1,减1后判断该弧头是否入度为0,是的话就入栈。直到所有顶点都出栈那么就输出了一个拓扑序列。但是这样做不能保证编号从小到大输出

为了保证从小到大输出,要用“每次都从头来过”的思想,因为题目保证一定存在拓扑序列,所以对于n个点,一定输出n次,所有外循环是次数,找到了n次,输出n个点,然后每次找,都是按照编号从1找到n,所以内循环是对应顶点的编号,从1到n,从当找到一个顶点,还没有纳入拓扑序列并且入度为0,就输出这个顶点的信息,并且扫描它的邻接表,将所有的弧头的入度都减1,然后再从头找过

所以找了n次,从次都是从编号1到n地扫描所有顶点,这样就能保证拓扑序列的正确性,而且因为编号都是从小到大扫描的,那么保证了先输出了编号小的

//用数组来实现邻接表
#include <stdio.h>
#include <string.h>
#define MAXN 510
#define MAXM 250100
bool g[MAXN][MAXN],vis[MAXN];  //g对应边集数组,体重可能有重复,vis记录那些顶点已经纳入序列
int u[MAXM],v[MAXM]; //保存弧u->v
int first[MAXN];  //对应每个顶点的邻接表的第一条弧的编号
int in[MAXN];     //对应每个顶点的入度
int nextt[MAXM];   //对应一条弧的下一弧的编号
int n,m;

void input()
{
int i,j,k;
memset(first , -1, sizeof(first));
memset(in,0,sizeof(in));
memset(g,0,sizeof(g));
for(i=0; i<m; i++)  //对应m条弧
{
scanf("%d%d",&u[i] , &v[i]);
if(g[u[i]][v[i]])  continue;
g[u[i]][v[i]]=1;
in[v[i]]++ ;
nextt[i]=first[u[i]];
first[u[i]]=i;
}
return ;
}
/*
void print_graph()
{
int i,j,k,t;
for(i=1; i<=n; i++)  //对应图的n个顶点,是从1开始标号的
{
printf("顶点%d:",i);
k=first[i];  //得到这个顶点的第一条弧
while(k!=-1)
{
printf(" %d",v[k]);
k=nextt[k];
}
printf("另外入度为%d\n",in[i]);
}
return ;
}
*/
void topsort()
{
int i,j,k,t,f;
memset(vis , 0 ,sizeof(vis));
for(f=0,i=1; i<=n; i++)  //从头找n次,输出全部n个顶点
{
for(j=1; j<=n; j++)  //对应n个顶点的标号
if(!vis[j] && in[j]<=0)  //zhe点还没有输出,而且这个点的入度为0,那么就是要输出这个点
break;
vis[j]=1;
if(!f)  printf("%d",j) , f=1;
else    printf(" %d",j);
t=first[j];   //找到第j个顶点的邻接表,找到它的第1条弧
while(t!=-1)
{
k=v[t];   //找到弧头元素
in[k]--;  //弧头元素的入度减1
t=nextt[t];   //第k条弧的下一条弧j
}
}
printf("\n");
return ;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
input(); //输入,建图
//        print_graph();
topsort();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: