蓝书(算法竞赛进阶指南)刷题记录——POJ1094 Sorting It All Out(最短路floyd)

本文详细解析了POJ1094题目的算法解决方案,利用差分约束和Floyd算法处理字母间的不等关系,通过二分查找或暴力枚举确定唯一顺序或产生矛盾的位置,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:POJ1094.
题目大意:给定 26 26 26个字母的 n n n组不等关系,格式为 x &lt; y x&lt;y x<y.现在要求输出最早能够确定唯一顺序或产生矛盾的位置,或输出没有这样一个位置,若有唯一顺序要输出顺序.
注意这道题的输出格式.

这道题一看想到了差分约束,仔细一想用floyd跑差分约束,然后发现好像确实可做.

我们用设 f [ i ] [ j ] f[i][j] f[i][j] t r u e true true表示 i &lt; j i&lt;j i<j,那么我们可以将所有关系转化,然后就可以跑一遍Floyd,接下来若有一对 x , y x,y x,y满足 f [ x ] [ y ] = f [ y ] [ x ] = t r u e f[x][y]=f[y][x]=true f[x][y]=f[y][x]=true,就说明矛盾,否则说明不矛盾.

要求出第几对之后矛盾,我们可以二分求解,或者也可以暴力枚举在第几对之后.

若不矛盾,我们要确定唯一顺序的话,我们可以发现若有唯一顺序的话,那么肯定满足一对 x , y x,y x,y不存在 f [ x ] [ y ] = f [ y ] [ x ] = f a l s e f[x][y]=f[y][x]=false f[x][y]=f[y][x]=false的情况.

求出唯一顺序可以使用暴力枚举每一个点,也可以直接使用拓扑排序求解.

至于求解在第几对之后,二分一下就好,当然也可以暴力枚举.

我这道题一开始以为它是要先判断所有边是否有矛盾或有唯一顺序,但是题目是要边读入边判.

代码如下:

//#include<bits/stdc++.h>
#include<iostream>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=26,M=N*N;
struct side{
  int x,y;
}e[M+9];
int n,m;
int flag,ans,pre[N+9];
int f[N+9][N+9];
void floyd(int mid){
  if (mid>m) mid=m;
  for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++)
      f[i][j]=0;
  for (int i=1;i<=mid;i++)
    f[e[i].x][e[i].y]=1;
  for (int k=1;k<=n;k++)
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++)
        f[i][j]|=f[i][k]&f[k][j];
}
bool check_con(int mid){
  if (mid>m) mid=m;
  floyd(mid);
  for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++)
      if (i^j&&f[i][j]&f[j][i]) return true;
  return false;
}
bool check_order(int mid){
  if (mid>m) mid=m;
  floyd(mid);
  for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++)
      if (i^j&&!(f[i][j]^f[j][i])) return false;
  return true;
}
char rc(){
  char c=getchar();
  while (c<'A'||c>'Z') c=getchar();
  return c; 
}
Abigail into(){
  char c1,c2;
  for (int i=1;i<=m;i++){
    c1=rc();c2=rc();
    e[i].x=c1-'A'+1;e[i].y=c2-'A'+1;
  }
}
Abigail work(){
  flag=2;
  for (int i=1;i<=m;i++){
    if (check_con(i)) flag=0;
    if (check_order(i)) flag=1;
    ans=i;
    if (flag^2) break;
  }
}
Abigail outo(){
  switch (flag){
    case 0:printf("Inconsistency found after %d relations.\n",ans);
           break;
    case 1:printf("Sorted sequence determined after %d relations: ",ans);
           floyd(ans);
           for (int i=1;i<=n;i++)
             pre[i]=0;      //查了一个下午错发现自己没有初始化pre为0...
           for (int i=1;i<=n;i++)
             for (int j=1;j<=m;j++)
               if (f[i][j]&&i^j) pre[j]++;
           for (int i=0;i<n;i++)
             for (int j=1;j<=n;j++)
               if (pre[j]==i) putchar(j-1+'A');
           putchar('.');putchar('\n');
           break;
    case 2:printf("Sorted sequence cannot be determined.\n");
           break;
  }
}
int main(){
  while (~scanf("%d%d",&n,&m)&&n){
    into();
    work();
    outo();
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值