题目链接

https://atcoder.jp/contests/agc037/tasks/agc037_d

题解

这场D题终于不像AGC032D和AGC036D一样神仙了……
还是可做的吧 虽然考场上没好好想赛后直接看题解了= =

考虑倒推,首先谁都能看出来第二次操作之后要让每一行是这一行对应元素的一个排列;
这样的话我们可以把数\(i\)最后应在的行视为它的颜色,第二次操作就是要把所有颜色\(i\)的数挪到第\(i\)列。
那么第一次操作之后,我们就是要让每列是颜色的一个排列。
考虑二分图匹配模型:
最关键的思路是从左往右考虑每一列
左边对每一行建一个点,右边对每种颜色建一个点
如果当前还没考虑的部分里这一行有色\(j\), 那么连边\((i,j)\)
跑一遍Dinic确定这一行的颜色,然后下一行重复此过程
为什么这样一定能解出来?考虑对\(M\)归纳,还剩下\(M\)行、每种颜色恰有\(M\)个的时候,对于任何行的集合\(S\), 其所包括的颜色数显然不小于\(|S|\), 根据Hall定理,存在完美匹配,转化为\(M-1\)的情况。
简单分析可得时间复杂度\(O(N^{3.5})\) (Dinic二分图匹配复杂度为边数乘以点数的平方根,默认\(N,M\)同阶)

代码

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;namespace NetFlow
{const int N = 202;const int M = 40400;const int INF = 1e7;struct Edge{int v,w,nxt,rev;} e[(M<<1)+3];int fe[N+3];int te[N+3];int dep[N+3];int que[N+3];int n,en;void addedge(int u,int v,int w){
//      printf("addedge%d %d %d\n",u,v,w);en++; e[en].v = v; e[en].w = w;e[en].nxt = fe[u]; fe[u] = en; e[en].rev = en+1;en++; e[en].v = u; e[en].w = 0;e[en].nxt = fe[v]; fe[v] = en; e[en].rev = en-1;}bool bfs(){for(int i=1; i<=n; i++) dep[i] = 0;int head = 1,tail = 1; que[tail] = 1; dep[1] = 1;while(head<=tail){int u = que[head]; head++;for(int i=fe[u]; i; i=e[i].nxt){if(dep[e[i].v]==0 && e[i].w>0){dep[e[i].v] = dep[u]+1;tail++; que[tail] = e[i].v;}}}return dep[2]!=0;}int dfs(int u,int cur){if(u==2) {return cur;}int rst = cur;for(int i=te[u]; i; i=e[i].nxt){if(dep[e[i].v]==dep[u]+1 && e[i].w>0 && rst>0){int flow = dfs(e[i].v,min(rst,e[i].w));if(flow>0){e[i].w-=flow; e[e[i].rev].w += flow; rst-=flow;if(e[i].w>0) {te[u] = i;}if(rst==0) {return cur;}}}}if(cur==rst) {dep[u] = 0;}return cur-rst;}void dinic(int _n){n = _n;int ret = 0;while(bfs()){for(int i=1; i<=n; i++) te[i] = fe[i];ret += dfs(1,INF);}
//      printf("ret=%d\n",ret);}void clear(){for(int i=1; i<=en; i++) e[i].v = e[i].w = e[i].nxt = e[i].rev = 0;for(int i=1; i<=n; i++) dep[i] = fe[i] = que[i] = te[i] = 0;n = en = 0;}
}
using NetFlow::e;
using NetFlow::fe;
using NetFlow::addedge;
using NetFlow::dinic;
using NetFlow::clear;const int N = 100;
int a[N+3][N+3];
int b[N+3][N+3];
vector<int> vec[N+3][N+3];
int tmp[N+3];
int n,m;int getclr(int x) {return (x-1)/m+1;}
bool cmp(int x,int y) {return getclr(x)<getclr(y);}int main()
{scanf("%d%d",&n,&m);for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&a[i][j]),vec[i][getclr(a[i][j])].push_back(a[i][j]);for(int k=1; k<=m; k++){for(int i=1; i<=n; i++){for(int j=1; j<=n; j++){if(vec[i][j].size()>0) {addedge(i+2,j+n+2,1);}}addedge(1,i+2,1);addedge(i+n+2,2,1);}dinic(n+n+2);for(int i=1; i<=n; i++){int u = i+2;for(int j=fe[u]; j; j=e[j].nxt){int v = e[j].v-n-2;if(v>0 && v<=n && e[j].w==0){
//                  printf("(%d,%d)\n",i,v);b[i][k] = *vec[i][v].rbegin();vec[i][v].pop_back();}}}clear();}for(int i=1; i<=n; i++) {for(int j=1; j<=m; j++) printf("%d ",b[i][j]); puts("");}for(int j=1; j<=m; j++){for(int i=1; i<=n; i++) tmp[i] = b[i][j];sort(tmp+1,tmp+n+1,cmp);for(int i=1; i<=n; i++) b[i][j] = tmp[i];}for(int i=1; i<=n; i++) {for(int j=1; j<=m; j++) printf("%d ",b[i][j]); puts("");}return 0;
}

AtCoder AGC037D Sorting a Grid (二分图匹配)相关推荐

  1. AtCoder AGC029F Construction of a Tree (二分图匹配)

    题目链接 https://atcoder.jp/contests/agc029/tasks/agc029_f 题解 考虑如何才能构成一棵树:显然有一个必要条件是对于每个点\(u\)来说,整张图所有的边 ...

  2. 2021牛客暑期多校训练营3 C Minimum grid 网络流 + 二分图匹配

    传送门 文章目录 题意: 思路: 题意: 给你一个n∗nn*nn∗n的矩阵,有mmm个点的位置需要填数,填的数范围是0≤k≤1e60\le k\le1e60≤k≤1e6,需要满足第iii行的最大值是b ...

  3. POJ 1486 Sorting Slides(二分图完全匹配必须边)题解

    题意:给你n张照片的范围,n个点的坐标,问你能唯一确定那几个点属于那几张照片,例如样例中4唯一属于A,2唯一属于C,1唯一属于B,3唯一属于C 思路:进行二分图完全匹配,怎么判断唯一属于?匹配完之后删 ...

  4. Dinic二分图匹配 || Luogu P3386

    题面:[模板]二分图匹配 思路:Dinic实现二分图匹配,要建一个超级源点(S)和超级汇点(T),分别定为N+M+1和N+M+2 然后S去和N中的数建正边和反边,正边权值为1,反边权值为0:M中的数去 ...

  5. 二分图匹配匈牙利算法DFS实现

    1 /*==================================================*\ 2 | 二分图匹配(匈牙利算法DFS 实现) 3 | INIT: g[][]邻接矩阵; ...

  6. poj1274(二分图匹配)

    (一道基础的二分图匹配) 题目意思大概为N个牛和M个栅栏,一个牛和一个栅栏只能匹配一次,求最大匹配 直接套用二分图最大匹配模板即可 #include <iostream> #include ...

  7. poj2724(二分图匹配)

    题目大概意思为有部分奶酪需要处理,若两个奶酪的二进制只有一位不同,则可以一起处理,问最少需要处理几次 题目思路: 将可以一起处理的两个奶酪用边连接在一起,相当于边只连接二进制中有偶数个1的奶酪和二进制 ...

  8. 算法模板——二分图匹配

    实现功能为二分图匹配 原理:匈牙利算法,核心思想--匹配上了就配,没直接匹配上也要通过前面的腾出位置让这个匹配上(详见:趣写算法系列之--匈牙利算法) 本程序以Codevs2776为例 详见Codev ...

  9. 算法:ACM二分图匹配 HDU2063

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2063 摘录于互联网,原创作者redraiment,很详细的二分图匹配入门资料! 2063 过山车 Pr ...

最新文章

  1. Selenium之XPATH轴定位(第三篇)
  2. jquery 获取前两个table里的每个tr里面的第二个td
  3. Eclipse中各种文件【默认编码格式设置】,防止乱码等问题
  4. autojs toast 可以改变字体颜色吗_喃喃札记 | 你真的需要一部pad做笔记吗?
  5. offset,client,scroll的学习记录
  6. Centos6.5 源码安装MySql5.6.33
  7. AUTOCAD——文本标注
  8. 360主机卫士Linux版,360主机卫士
  9. html 收藏网站 功能实现,网站常用的收藏网站实现代码
  10. EDEM2019 实例操作教程——输送带
  11. ESP32笔记(2) flash使用
  12. 软考高项记忆小妙招-项目章程
  13. 解决aab上传GooglePlay超过150M的问题及aab包测试方法
  14. 抖音快手如何快速涨粉技巧整理
  15. 延长SQLyog试用期
  16. 网易校招编程题目之牛牛分苹果
  17. git 更新某个目录或文件
  18. Codeforces Round #840 (Div. 2) and Enigma 2022 - Cybros LNMIIT题解
  19. 程序员的自我进化:互联网公司套路多,如何避免自己被无偿辞退?
  20. pdm生成java_Powerdesigner逆向工程从现有数据库生成PDM

热门文章

  1. matlab将脚本导出动态库文件.dll,并被python调用
  2. vnc连接linux使用教程_linux系统下vnc 的配置和使用方法
  3. Memcache参数
  4. 常用javascript代码
  5. js库prototype中的$()
  6. 访问DBGRIDEH中的行与列
  7. BUUCTF-WEB:[强网杯 2019]随便注 1
  8. 程序员面试系列——插入排序
  9. /proc文件系统读出来的数据是最新的吗?
  10. CSDN-markdown编辑器使用方法