Poj 3660 Cow Contest——弗洛伊德算法+拓扑排序

题目链接:

http://poj.org/problem?id=3660


题目大意:

有n头牛,给定n头牛的先后关系,按照这个先后关系给n头牛排序。

当然,有些牛的位置是可以确定的,而有些牛的位置是不确定的。求能确定位置的牛的头数。


解题思路:

采用拓扑排序。

当前状态,如果入度为0的点不止一个,那么很显然,这些点都不能确定位置。

如果入度为0的点的只有一个,那么我们就需要判断,该点的祖先的个数是否等于已经删除的点的个数,

如果相等的话,那么这个点的位置就是可以确定的。

寻找祖先节点的方法比较暴力,用的是弗洛伊德算法。

注意:弗洛伊德算法三重循环的顺序,第1重循环必须是枚举中间节点,这样才能保证所有的点对都能被更新。


源代码:

//先用弗洛伊德法求解每个节点的祖先个数
//然后进行拓扑排序
//采用邻接矩阵存储
//这个题目还要考虑出现了环的情况
#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<string.h>
#include<math.h>
#include<cmath>
#include<vector>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
int s[105][105];
int s1[105][105];
int d[105];
int pre[105];
int son[105];
vector<int> v;
int n,m,ans;
void Floyd()
{
    int i,j,k;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            s1[i][j]=s[i][j];
        for(k=1;k<=n;k++)
            for(i=1;i<=n;i++)
                for(j=1;j<=n;j++)   //中间点
                    if(s1[i][k] && s1[k][j])
                        s1[i][j]=1;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            if(s1[i][j])
            {
                pre[j]++;
               // son[i]++;
            }
//    ans=0;
//    for(i=1;i<=n;i++)
//        if(pre[i]+son[i]==n-1)
//            ans++;
//    printf("%d\n",ans);
    return;
}
void top_sort()
{
    int i,j,k,t,len,cnt;
    cnt=ans=0;
    while(1)
    {
        v.clear();
        for(i=1;i<=n;i++)
            if(d[i]==0)
                v.push_back(i);
        len=v.size();
        if(len==0)      //没有找到这样的点,直接退出
            break;
        k=v[0];
        //如果当前只有一个点的度数为0,并且该点祖先的个数等于已经删掉的点的个数,那么该点的位置是可以确定的
        if(len==1 && pre[k]==cnt)
            ans++;
        cnt+=len;
        for(i=0;i<len;i++)
        {
            k=v[i];
            d[k]=-1;
            for(j=1;j<=n;j++)
                if(s[k][j])
                    d[j]--;
        }
    }
    printf("%d\n",ans);
    return;
}
int main()
{
    freopen("in.txt","r",stdin);
    int a,b,i,j,k,t;
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(s,0,sizeof(s));
        memset(d,0,sizeof(d));
        memset(pre,0,sizeof(pre));
        memset(s1,0,sizeof(s1));
        memset(son,0,sizeof(son));
        while(m--)
        {
            scanf("%d%d",&a,&b);
            if(!s[a][b])    //考虑重边的情况
                d[b]++;
            s[a][b]=1;
        }
        Floyd();        //采用floyd算法计算出每个节点祖先的个数
        top_sort();     //然后进行拓扑排序
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值