POJ 1094 Sorting It All Out (拓扑排序,有向图判环)

题目链接:http://poj.org/problem?id=1094

思路:因为要找第一个满足拓扑排序的或是有环的,所以要从第一个输入就开始判断。这里要注意一点,如果判断时发现有环了,那么后面都不用管了,答案就是有环;如果判断时发现满足拓扑排序了,那么后面也不用管了(不管后面有没有和前面形成环),答案就是满足拓扑。

        先判断环,再判断拓扑排序比较方便。判环时,可以用DFS,方法如下,令vis[i] == 0表示结点i还没被访问、vis[i] == -1表示结点正在访问、vis[i] == 1表示节点已访问完成,如果在访问的过程中发现某个子结点的vis为-1,则存在环。若结点i访问完成并且没有环,则令vis[i] == 1,后面再扫到v时直接跳过即可(因为i点不在环中)。

       判断完环后,再判断拓扑排序就简单了(这里的拓扑排序是必须满足任意两点都可比较)。从图中找入度为0的结点,若个数大于1,则不满足,否则删除该点即该点所连的边,继续重复前面的过程,直到所有点被删光为止。


    

#include<cstdio>
#include<cstring>
#include<string>
#include<cctype>
#include<iostream>
#include<set>
#include<map>
#include<cmath>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<bitset>
#include<algorithm>
#define fin() freopen("A.txt","r",stdin)
#define fout() freopen("B.txt","w",stdout)
typedef long long ll;
using namespace std;
const int maxn = 30;
string ans;
vector<int> G[maxn];
int vis[maxn];
int degree[maxn];
int n, m;

bool dfs(int u) {
  if(vis[u] == -1) return false;
  vis[u] = -1;
  for(int i = 0; i < G[u].size(); i++) {
    int v = G[u][i];
    if(vis[v] == 1) continue;
    if(!dfs(v)) return false;
  }
  vis[u] = 1;
  return true;
}

bool is_circle() {
  memset(vis, 0, sizeof vis);
  for(int i = 0; i < n; i++) if(!vis[i]){
    if(!dfs(i)) return true;
  }
  return false;
}

bool is_topo() {
  string s;
  int ru[maxn];
  memset(vis, 0, sizeof vis);
  for(int i = 0; i < n; i++) ru[i] = degree[i];
  bool ok = true;
  for(;;) {
    int cnt = 0, temp = 0;
    for(int i = 0; i < n; i++) {
      if(!ru[i] && !vis[i]) {
        cnt++; vis[i] = 1; temp = i;
      }
    }
    if(cnt != 1) {
      if(cnt > 1) ok = false;
      break;
    }
    s += (char)(temp+'A');
    for(int i = 0; i < G[temp].size(); i++) {
      int v = G[temp][i];
      ru[v]--;
    }
  }
  if(ok) ans = s;
  return ok;
}

int main() {

  while(scanf("%d%d", &n, &m) && n) {

    memset(degree, 0, sizeof degree);
    for(int i = 0; i < n; i++) G[i].clear();
    int circle = 0, topo = 0;
    
    for(int i = 1; i <= m; i++) {
      char s[5]; scanf("%s" ,s);
      if(circle || topo) continue;
      int u = s[0] - 'A', v = s[2] - 'A';
      degree[v]++;
      G[u].push_back(v);
      
      if(is_circle()) circle = i;
      if(!circle && !topo && is_topo()) topo = i;
    }
    
    if(circle) printf("Inconsistency found after %d relations.\n", circle);
    else if(topo) printf("Sorted sequence determined after %d relations: %s.\n", topo, ans.c_str());
    else printf("Sorted sequence cannot be determined.\n");
    
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值