[CF1131D]Gourmet Choice 题解

题意:有两组食物,分别有\(n\)个和\(m\)个。
给定\(n\times m\)的一个表格,其中\(a[i][j]\)表示第一组第\(i\)个食物和第二组第\(j\)个食物的美味度大小关系。
请问是否能给出一组美味度方案。如果有,请给出美味度最大值最小的方案。如果没有,请输出No.

先膜LCJ
本题如果数据出小一点就是差分约束系统的裸题。
但是到了现在的数据大小,差分约束无法承受,所以考虑用并查集+拓扑排序解决。
=的食物用并查集并起来。然后对于><的情况,如果这俩元素在一个联通块里,显然不能构造
否则,如果\(a[i][j]= '<'\)就从\(i\)的连通块向\(j\)连一条边,反之亦然。
然后对联通块跑拓扑排序即可。注意有环也不能构造
正确性很显然:对于\(v\),如果被删成了入度\(=0\),那么上一次它只需要满足\(u\)的限制即可。
\(value[v] = value[u] + 1\).

/**
 * @Author: Mingyu Li
 * @Date:   2019-03-09T22:42:11+08:00
 * @Email:  [email protected]
 * @Filename: c1131D.cpp
 * @Last modified by:   Mingyu Li
 * @Last modified time: 2019-03-10T06:53:10+08:00
 */

#include <bits/stdc++.h>
#define tpname typename
#define Go(i , x , y) for(register int i = x; i <= y; i++)
#define God(i , y , x) for(register int i = y; i >= x; i--)
typedef long long LL;
typedef long double ld;
typedef unsigned long long ULL;
template < tpname T > void sc(T& t) {
  char c = getchar(); T x = 1; t = 0; while(!isdigit(c)) {if(c == '-') x = -1; c = getchar();}
  while(isdigit(c)) t = t * 10 + c - '0' , c = getchar();t *= x;
}
template < tpname T , tpname... Args > void sc(T& t , Args&... args) {sc(t); sc(args...);}
template < tpname T > T mul(T x , T y , T _) {
  x %= _,y %= _; return ((x * y - (T)(((ld)x * y + 0.5) / _) * _) % _ + _) % _;
}

const int N = 1000 + 5;
int f[N + N];
int find(int x) {
  return x == f[x] ? f[x] : f[x] = find(f[x]);
}
std::vector <int> v[N + N] , Graph[N + N];
std::map <std::pair<int,int>,int> alr;
char a[N][N];
int n , m;

int merge(int u , int v) {
  f[find(u)] = find(v);
}
int rf;
int degree[N + N] , ans[N + N];
void Link(int u , int v) {
  if(u == v)  {
    rf = 1;
    return ;
  }
  if(alr[{u , v}]) return ;
  alr[{u , v}] = 1;
  Graph[u].push_back(v);
  ++degree[v];
}
int main() {
  sc(n , m);
  Go(i , 1 , n)
    scanf("%s" , (a[i] + 1));
  Go(i , 1 , n+m) f[i] = i;
  Go(i , 1 , n) Go(j , 1 , m) if(a[i][j] == '=') merge(i , n+j);
  std::vector <int> v1;
  Go(i , 1 , n+m) v[find(i)].push_back(i) , v1.push_back(find(i));
  Go(i , 1 , n)
    Go(j , 1 , m) {
      if(a[i][j] == '<') Link(find(i) , find(n+j));
      else if(a[i][j] == '>') Link(find(n+j) , find(i));
    }
  if(rf) {
    puts("No");
    return 0;
  }
  std::queue <std::pair <int , int> > Q;


  sort(v1.begin() , v1.end());
  int m1 = unique(v1.begin() , v1.end()) - v1.begin();
  std::vector <int> v2;
  Go(i , 0 , m1-1) if(!degree[v1[i]]) {
    Q.push({v1[i] , 1}); v2.push_back(v1[i]);
    for(auto fix : v[v1[i]]) ans[fix] = 1;
  }

  while(!Q.empty()) {
    std::pair < int , int > x = Q.front(); Q.pop();
    int u = x.first , va = x.second;
    for(auto vv : Graph[u]) {
      degree[vv]--;
      if(!degree[vv]) {
        degree[vv] = 0;
        Q.push({vv , va + 1});
        v2.push_back(vv);
      }
    }
  }

  Go(i , 0 , v2.size() - 1) {
    for(auto fix : v[v2[i]]) ans[fix] = i + 1;
  }
  int ans1 = 0;
  Go(i , 1 , n+m) ans1 += (degree[find(i)] == 0);
  //std::cerr << "\n";
  if(ans1 != n+m) {
    puts("No");
    return 0;
  }

  std::cout << "Yes\n";
  Go(i , 1 , n) std::cout << ans[i] << " ";
  std::cout << "\n";
  Go(i , 1 , m) std::cout << ans[n + i] << " ";
  std::cout << "\n";
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/LiM-817/p/10887242.html