• AtCoder Beginner Contest 277 F. Sorting a Matrix(拓扑排序+虚点)


    题目

    n*m(2<=n,m<=1e6,n*m<=1e6)的矩阵,

    第i行第j列元素a[i][j](0<=a[i][j]<=n*m)

    对于值为0的元素,你可以将其赋值为任意正整数,

    不同位置的0元素,可以被赋值成不同的正整数

    然后,你可以执行以下操作若干次:

    1. 选择行i和行j,对于k∈[1,m],交换a[i][k]和a[j][k]

    2. 选择列i和列j,对于k∈[1,n],交换a[k][i]和a[k][j]

    若干次操作后,问矩阵是否能满足以下条件:

    • A1,1​≤A1,2​≤⋯≤A1,W​≤A2,1​≤A2,2​≤⋯≤A2,W​≤A3,1​≤⋯≤AH,1​≤AH,2​≤⋯≤AH,W​

    即每一行行内非严格递增,且第i行的最大值不超过第i+1的最大值

    思路来源

    官方题解

    题解

    首先,0是可以被忽略的,假设在一个非严格递增序列中插入0,

    则0总可以赋值成其相邻左侧,或相邻右侧的值,使得序列的非严格递增性质保持不变

    然后,矩阵会有一个行限制和一个列限制

    1. 行限制,记每一行的最小值和最大值(mn,mx),然后按mn排增序,

    则排增序之后,第i项的mx需要小于等于第i+1项的mn

    2. 列限制,行操作完之后,每次只能交换两列,若干次操作后,

    相当于找到一个列号的排列,使得每一行内成非严格递增

    对于同一行不同列内的两个值来说,若j1列的值v1

    连一条边之后,相当于需要对m列确定一个拓扑序,

    但如果对每一行暴力连边,一行内的边数最多是C(m,2)的,总数n*C(m,2),不能接受

    假设有两列的值是1,两列的值是2,考虑按如下图示,优化建边数

    优化后,总的点数大致在2e6级别,而边数也大致在4e6级别,直接topo排序即可

    图示

    暴力连边

     建虚点x连边

    心得

    虚点的做法,典中典

    之前只是在最短路中搞过虚点,实际这题说明,

    需要连n*m条边的场合,都可以考虑尝试是不是能优化成n+m条边的

    代码

    1. #include
    2. using namespace std;
    3. typedef long long ll;
    4. typedef pair<int,int> P;
    5. const int N=2e6+10,INF=0x3f3f3f3f;
    6. int n,m,in[N],tot,id;
    7. P b[N],x[N];
    8. vector<int>e[N];
    9. queue<int>q;
    10. void add(int u,int v){
    11. e[u].push_back(v);
    12. in[v]++;
    13. }
    14. int main(){
    15. scanf("%d%d",&n,&m);
    16. vectorint>>a(n+1,vector<int>(m+1,0));
    17. id=m;
    18. for(int i=0;i
    19. int c=0,cnt=0,mn=N,mx=0;
    20. for(int j=0;j
    21. scanf("%d",&a[i][j]);
    22. cnt+=(!a[i][j]);
    23. if(a[i][j]){
    24. x[c++]=P(a[i][j],j);
    25. mn=min(mn,a[i][j]);
    26. mx=max(mx,a[i][j]);
    27. }
    28. }
    29. if(cnt==m)continue;
    30. b[tot++]=P(mn,mx);
    31. sort(x,x+c);// 列限制
    32. int las=-1;
    33. for(int j=0;j
    34. int k=j;
    35. while(k+11].first==x[k].first)k++;
    36. if(~las)for(int l=j;l<=k;++l)add(las,x[l].second);
    37. las=id++;
    38. for(int l=j;l<=k;++l)add(x[l].second,las);
    39. j=k+1;
    40. }
    41. }
    42. sort(b,b+tot);// 行限制
    43. for(int i=1;i
    44. if(b[i-1].second>b[i].first){
    45. cout<<"No"<
    46. return 0;
    47. }
    48. }
    49. for(int i=0;i
    50. if(!in[i])q.push(i);
    51. }
    52. while(!q.empty()){
    53. int u=q.front();q.pop();
    54. id--;
    55. for(auto &v:e[u]){
    56. if(!(--in[v])){
    57. q.push(v);
    58. }
    59. }
    60. }
    61. cout<<(!id?"Yes":"No")<
    62. return 0;
    63. }

  • 相关阅读:
    HTML班级网页设计 基于HTML+CSS+JS制作我们的班级网页(web前端学生网页设计作品)
    Polygon zkEVM R1CS与Plonk电路转换
    动态规划合集
    Python爬虫--Requests 库用法大全
    Linux 系统执行ls 命令出现 Input/output error 解决妙招
    向毕业妥协系列之机器学习笔记:高级学习算法-神经网络(一)
    Kotlin学习(一)
    pytorch初学笔记(六):DataLoader的使用
    链设计模式-装饰模式、职责链设计模式
    ts的文字类型
  • 原文地址:https://blog.csdn.net/Code92007/article/details/128069245