lightoj1003 Drunk 、uva10305 Ordering Tasks (基于dfs的拓扑排序)

uva10305

题意很简单,给你几个任务,这几个任务之间有先做和后做的顺序,如果a,b之间有顺序的话,就必须在做b之前先把a做了,然后问你做这几件事的一个可能的顺序是什么(答案可能不唯一,只要满足要求即可)。

这道题很基础的一道拓扑排序,由于数据很小,可以采用矩阵来存储图;关于拓扑排序网上也有很多讲解,感觉dfs这种比较容易理解一点吧,在《算法竞赛入门经典》第二版167页讲解有;

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#define INF 0x3f3f3f3f
#define N 200
using namespace std;
int G[N][N];
int c[N],top[N],t,n;
bool dfs(int u)
{
    c[u]=-1;//c[u]=0表示该点没被访问过,c[u]=-1表示正在访问,c[u]=1表示已经访问过;
    int i;
    for(i=1; i<=n; i++)
    {
        if(G[u][i])
        {
            if(c[i]<0)//如果正在访问的点它的后继为-1的话说明该点再次出现了,代表有环,失败退出;
                return false;
            else if(!c[i]&&!dfs(i))//如果正在访问的点它的后继中某个点在求dfs时,dfs为假,则说明正在访问的点它的后继中某个点再次出现了,则后继中有环,失败退出
                return false;
        }

    }
    c[u]=1;
    top[t--]=u;//由于是递归调用,所以应当倒着存储;
    return true;
}
bool topsort()
{
    int i;
    t=n;
    memset(c,0,sizeof(c));
    for(i=1; i<=n; i++)
        if(!c[i])
        {
            if(!dfs(i))
                return false;
        }
    return true;
}
int main()
{
    int m,i,a,b;
    while(1)
    {
        scanf("%d%d",&n,&m);
        if(m==0&&n==0)
            break;
        memset(G,0,sizeof(G));
        for(i=1; i<=m; i++)
        {
            scanf("%d%d",&a,&b);
            G[a][b]=1;
        }
        topsort();
        for(i=1; i<=n; i++)
            printf("%d%c",top[i],i==n?'\n':' ');
    }
    return 0;
}
上面的方法是用邻接矩阵的方法存储的,但是当数据量过大的时候用矩阵存储肯定会爆内存的,这时候就可以用STL中容器来存储;

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#define INF 0x3f3f3f3f
#define N 200
using namespace std;
int c[N],top[N],t,n;
vector<int>G[N];//用容器存储邻接表
bool dfs(int u)
{
    c[u]=-1;
    int i;
    for(i=0; i<G[u].size(); i++)
    {

            if(c[G[u][i]]<0)
                return false;
            else if(!c[G[u][i]]&&!dfs(G[u][i]))
                return false;


    }
    c[u]=1;
    top[t--]=u;
    return true;
}
bool topsort()
{
    int i;
    t=n;
    memset(c,0,sizeof(c));
    for(i=1; i<=n; i++)
        if(!c[i])
        {
            if(!dfs(i))
                return false;
        }
    return true;
}
int main()
{
    int m,i,a,b;
    while(1)
    {
        scanf("%d%d",&n,&m);
        if(m==0&&n==0)
            break;
        for(i=0;i<=n;i++)
            G[i].clear();
        for(i=1; i<=m; i++)
        {
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
        }
        topsort();
        for(i=1; i<=n; i++)
            printf("%d%c",top[i],i==n?'\n':' ');
    }
    return 0;
}
这样一来即使数据过大也不会爆内存了;

lightoj 1003

这道题也是个拓扑排序,只需要用map转化一下数字就行了,不过这道题数据过大,用邻接矩阵存储会爆内存,这时候就可以用上面说的用容器实现邻接表的存储了;

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#define INF 0x3f3f3f3f
#define N 20010
using namespace std;
int c[N],top[N],t,n;
map<string,int>mp;
vector<int>G[N];
int str(string s)//利用map实现由字符串到数字的转化
{
    if(!mp[s])
    {
        mp[s]=++n;
        return n;
    }
    return mp[s];
}
bool dfs(int u)
{
    c[u]=-1;
    int k=G[u].size();
    for(int i=0; i<k; i++)
    {
        if(c[G[u][i]]<0)
            return false;
        else if(!c[G[u][i]]&&!dfs(G[u][i]))
            return false;
    }
    c[u]=1;
    top[--t]=u;
    return true;
}
bool topsort()
{
    int i;
    t=n;
    memset(c,0,sizeof(c));
    for(i=1; i<=n; i++)
        if(!c[i])
        {
            if(!dfs(i))
                return false;
        }
    return true;
}
int main()
{
    int T,i,m,a,b;
    string s1,s2;
    int k=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&m);
        n=0;
        mp.clear();
        for(i=0; i<=m*2; i++)//记得清空,是2*m的大小
            G[i].clear();
        for(i=0; i<m; i++)
        {
            cin>>s1>>s2;
            a=str(s1);
            b=str(s2);
            G[a].push_back(b);
        }
        if(topsort())
            printf("Case %d: Yes\n",++k);
        else
            printf("Case %d: No\n",++k);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值