• 【AT5161】[AGC037D] Sorting a Grid(二分图匹配)


    点此看题面

    • 给定一个(n imes m)的矩阵(A),你可以将(A)每一行任意重排得到(B),将(B)每一列任意重排得到(C),将(C)每一行任意重排得到(D)
    • 要求(D)((i,j))格子上的数是((i-1) imes m+j),求构造一组合法的(B,C)
    • (n,mle100)

    题意转化

    反向考虑,要让最终(D)满足这样的条件,因为(C)(D)只能对于行重排,就需要让每一行的数都正确。

    又由于(B)(C)只能对于列重排,所以(B)的每一列中应该同时包含每种行的元素。

    所以说,给最终第(i)行的元素赋上一个颜色(i),我们的问题就变成了,对(A)进行行重排,让每一列都能包含所有颜色的元素。

    二分图匹配

    经典的二分图匹配问题,对于每个元素,从它所在的行对应的点向它的颜色对应的点连边。

    显然这是一张二分图,而一对完美匹配就意味着一列的填法。

    因此只要跑(m)次匈牙利算法就结束了。

    代码:(O(n^2m^2))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100
    using namespace std;
    int n,m,a[N+5][N+5],p[N+5][N+5],b[N+5][N+5],e[N+5][N+5];
    int s[N+5],vis[N+5];I bool Match(CI x,CI ti) {for(RI i=1;i<=n;++i)//匈牙利算法
    	if(e[x][i]&&vis[i]^ti&&(vis[i]=ti,!s[i]||Match(s[i],ti))) return s[i]=x;return 0;}
    int main()
    {
    	RI i,j;for(scanf("%d%d",&n,&m),i=1;i<=n;++i) for(j=1;j<=m;++j) scanf("%d",&a[i][j]),++e[p[i][j]=(a[i][j]-1)/m+1][i];//记录每行和每种颜色间的边数
    	RI k;for(i=1;i<=m;++i) {for(j=1;j<=n;++j) s[j]=vis[j]=0;for(j=1;j<=n;++j) Match(j,j);//做m次二分图匹配
    		for(j=1;j<=n;++j) for(--e[s[j]][j],k=1;k<=m;++k) if(p[j][k]==s[j]) {b[i][j]=a[j][k],p[j][k]=0;break;}}//求出该列的填法
    	for(i=1;i<=n;putchar('
    '),++i) for(j=1;j<=m;++j) printf("%d ",b[j][i]);for(i=1;i<=m;++i) sort(b[i]+1,b[i]+n+1);//直接输出b,然后给每列排序
    	for(i=1;i<=n;putchar('
    '),++i) for(j=1;j<=m;++j) printf("%d ",b[j][i]);return 0;//输出c
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    DrawerLayout侧滑菜单
    pagerslidingtabstrip 横向滑动
    Android对话框
    关于不同页面的传参分析
    ajax异步传输数据,return返回值为空
    mCustomScrollbar 滚动条的使用
    angular实现表格的全选、单选、部分删除以及全部删除
    iOS风格的弹出框(alert,prompt,confirm)
    下拉刷新,上拉加载功能--dropload.js的使用
    页面水印效果的实现--新篇
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT5161.html
Copyright © 2020-2023  润新知