F - Sorting a Matrix(拓扑&缩点)

该博客讨论了如何对矩阵进行行和列的特定排序,行排序通过预处理实现,列排序则利用拓扑关系和缩点策略。文章提到了时间复杂度为O(nm),并提供了两种不同的解决方案,一种涉及拓扑排序,另一种通过对列直接排序并进行特判。此外,还探讨了排序过程中特殊情况的处理,如相同元素的列如何简化连接。

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

F - Sorting a Matrix(拓扑&缩点)

行、列可以独立成两个问题。

行要求上一行的mini≤maxi≤mini+1≤maxi+1,i<nmin_i\le max_i \le min_{i+1}\le max_{i+1} ,i <nminimaximini+1maxi+1,i<n

这个预处理一波排序即可,0跳过。

列的话,考虑拓扑关系,每列建立关系,注意某一行值相同得列,可以缩点

比如c1=c2=c3<c4=c5=c6c_1=c_2=c_3<c_4=c_5=c_6c1=c2=c3<c4=c5=c6 那么我们新建一个点c7c_7c7

c1,c2,c3c_1,c_2,c_3c1,c2,c3c7c_7c7c7c_7c7c4,c5,c6c_4,c_5,c_6c4,c5,c6。 就不需要每对点都连了。

时间复杂度:O(nm)O(nm)O(nm)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int h, w;
int a[1000005];
vector<int> G[2000005];
bool used[2000005];
vector<int> topo;

void dfs(int v)
{
  used[v] = true;
  for(auto u : G[v]) if(!used[u]) dfs(u);
  topo.push_back(v);
}

int main(void)
{
  cin >> h >> w;
  for(int y = 1; y <= h; y++) for(int x = 1; x <= w; x++) cin >> a[(y-1)*w+(x-1)];
  
  vector<pair<int,int>> vec;
  for(int y = 1; y <= h; y++){
    int l = 1e9, r = -1e9;
    for(int x = 1; x <= w; x++){
      int v = a[(y-1)*w+(x-1)];
      if(v) l = min(l, v), r = max(r, v);
    }
    if(l <= r) vec.push_back({l, r});
  }
  sort(vec.begin(), vec.end());
  
  for(int i = 1; i < (int)vec.size(); i++){
    if(vec[i-1].second > vec[i].first){
      cout << "No"<< endl;
      return 0;
    }
  }
  
  for(int y = 1; y <= h; y++){
    vector<pair<int, int>> vec;
    for(int x = 1; x <= w; x++) if(a[(y-1)*w+(x-1)]) vec.push_back({a[(y-1)*w+(x-1)], x});
    sort(vec.begin(), vec.end());
    
    for(int i = 1; i < (int)vec.size(); i++){
      if(vec[i-1].first != vec[i].first){
        int v = w + vec[i-1].first;
        for(int j = i-1; j >= 0; j--){
          if(vec[j].first != vec[i-1].first) break;
          G[vec[j].second].push_back(v);
        }
        for(int j = i; j < (int)vec.size(); j++){
          if(vec[j].first != vec[i].first) break;
          G[v].push_back(vec[j].second);
        }
      }
    }
  }
  
  int n = w + h*w;
  for(int i = 1; i <= n; i++) if(!used[i]) dfs(i);
  reverse(topo.begin(), topo.end());
  
  for(int i = 1; i <= n; i++) used[i] = false;
  for(auto v : topo){
    used[v] = true;
    for(auto u : G[v]){
      if(used[u]){
        cout << "No" << endl;
        return 0;
      }
    }
  }
  cout << "Yes" << endl;

  return 0;
}

貌似列问题还可以直接对每列排序,然后特判。

不知道为啥排序得复杂度为啥对得,当两列相同得时,cmp为啥直接返回0.

#include<bits/stdc++.h>
using namespace std;
int n,m,x,ov;
bool cmp(vector<int> &a,vector<int> &b){
    bool res=ov;
    for(int i=0;i<n;i++){
        if(a[i]&&b[i]&&a[i]!=b[i]){
            res=1;
            if(a[i]>b[i]) return 0;
        }
    }
    return res;
}
int main() {
    cin>>n>>m;
    vector<vector<int> >  cv(m);
    vector<pair<int,int>> rg;
    for(int i=0;i<n;i++){
        int mx=0,mn=10000000;
        for(int j=0;j<m;j++){
            cin>>x;
            cv[j].push_back(x);
            if(x) mx=max(mx,x),mn=min(mn,x);
        }
        if(mx) rg.push_back({mn,mx});
    }
    sort(rg.begin(),rg.end());
    for(int i=1;i<rg.size();i++){
        if(rg[i-1].second>rg[i].first) return puts("No"),0;
    }
    sort(cv.begin(),cv.end(),cmp);
    ov=1;
    for(int i=0;i<m-1;i++) if(!cmp(cv[i],cv[i + 1])) return puts("No"),0;
    puts("Yes");
    return 0;
}   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷酷的Herio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值