拓扑排序

拓扑排序经典运用于判断有向图种是否存在环。

拓扑排序的遍历也一定是无环的。

经典例题为:洛谷:https://www.luogu.com.cn/problem/P1347

同题:poj:http://poj.org/problem?id=1094  fjut:http://120.78.128.11/Problem.jsp?pid=1516

下面是ac代码和解释,带有几组数据。

这个题本人做了大概两三遍吧,

今天再做一次都还是wa了得90分,细节东西还是多

(wa点是:把add建边写在了bfs判断环的条件执行内,实际上建边根判断环并不存在条件关系,且如果有环而未建边,会导致答案应该是成环矛盾,而变成了有拓扑排序解,针对于A->A这种数据会wa掉。)

复制代码
#include<bits/stdc++.h> 
#include<algorithm>
using namespace std;
#define N 202
#define mt(x) memset(x,0,sizeof x)
typedef long long ll;
void cn(ll x){cout<<x<<endl;}
void cs(string x){cout<<x<<endl;}
int n,m;
int mp[N][N],in[N],inn[N],num;
bool pd,vis[N],v[N];
char ans[N];
void add(int x,int y)
{
    in[y]++;
    mp[x][y]=1;
    if(!v[x]){num++;v[x]=1;}
    if(!v[y]){num++;v[y]=1;}
}
bool bfs(int x,int y)
{
    mt(vis);
    queue<int>q;
    q.push(x);
    while(q.size())
    {
        x=q.front();q.pop();
        vis[x]=1;
        for(int i=0;i<n;++i)
        {
            if(mp[x][i])
            {
                if(i==y)return false;
                if(!vis[i])
                {
                    vis[i]=1;
                    q.push(i);
                }
            }
        }
    }
    return true;
}
void topo(int i)
{
    int cnt=0;mt(vis);mt(ans);
    queue<int>q;
    for(int i=0;i<n;++i)
    {
        inn[i]=in[i];
        if(!in[i])q.push(i);
    }
    while(q.size())
    {
        int x=q.front();q.pop();
        vis[x]=1;
        ans[cnt++]='A'+x;
        //cs(ans);
        //每次队列里必须只有一个元素,所以pop后队列为空 ,否则退出 
        if(q.size())return ;
        for(int i=0;i<n;++i)
        {
            if(mp[x][i]==1)
            {
                inn[i]--;
                //cout<<"  to->"<<char(i+'A')<<endl; 
                if(!vis[i]&&!inn[i])
                {
                    vis[i]=1;
                    q.push(i);
                    //cout<<"       入:"<<char(i+'A')<<endl;
                }
            }
        }
    }
    if(cnt==n)
    {
        pd=false;
        cout<<"Sorted sequence determined after "<<i<<" relations: "<<ans<<'.'<<endl;
        //cs("ans1"); 
    }
}
void solve()
{
    cin>>n>>m;
    pd=true;num=0;
    for(int i=1;i<=m;++i)
    {
        string s;cin>>s;
        add(s[0]-'A',s[2]-'A');
        if(!bfs(s[2]-'A',s[0]-'A')&&pd)
        {
            pd=false;
            cout<<"Inconsistency found after "<<i<<" relations."<<endl;
            //cs("ans2");
        }
        if(num==n&&pd)topo(i);//给定的边已涉及到n个点,即可以开始进行拓扑排序
    }
    if(pd)cs("Sorted sequence cannot be determined.");//cs("ans3");
}
/*
分析3种情况
正常排序:在已入边元素数=n 开始判断是否排序成功 ,完美的拓扑排序为每次队列循环只有一个新元素入队 
矛盾:bfs判断环
无法排序:点数不够or一次循环入队有多种情况 

建图
a<b
b在a之后,即in[b]++;

示例数据 

4 6
C<D
C<B
B<A
C<D
D<A
A<A
Inconsistency found after 6 relations.
AA边为矛盾 

6 6
A<F
B<D
C<E
F<D
D<E
E<F
Inconsistency found after 6 relations.
这个是针对多选的情况,本题是不认可的,会判断为矛盾 

5 5
A<B
B<C
C<D
D<E
E<A
Sorted sequence determined after 4 relations: ABCDE
顺序判读即可,第四个有完美拓扑排序,不必考虑第五个矛盾的情况 

4 6
A<B
A<C
B<C
C<D
B<D
A<B
Sorted sequence determined after 4 relations: ABCD.
基本样例 
*/
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    solve();
    return 0;
}
复制代码

 如果是多组输入

需要初始化

void init()
{
    pd=true;num=0;
    mt(mp);mt(in);mt(v);mt(ans);
}

 

posted @   Renhr  阅读(70)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示