题目链接

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. Sorting Slides(二分图匹配——确定唯一匹配边)

    题目描述: Professor Clumsey is going to give an important talk this afternoon. Unfortunately, he is not ...

  2. POJ 1486 Sorting Slides【二分图匹配】

    题目大意:有n张幻灯片和n个数字,幻灯片放置有重叠,每个数字隶属于一个幻灯片,现在问你能够确定多少数字一定属于某个幻灯片 思路:上次刷过二分图的必须点后这题思路就显然了 做一次二分匹配后将当前匹配的边 ...

  3. POJ 1486 Sorting Slides(二分图匹配)

    [题目链接] http://poj.org/problem?id=1486 [题目大意] 给出每张幻灯片的上下左右坐标,每张幻灯片的页码一定标在这张幻灯片上, 现在问你有没有办法唯一鉴别出一些幻灯片 ...

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

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

  5. AtCoder Regular Contest 092 C - 2D Plane 2N Points(二分图匹配)

    Problem Statement On a two-dimensional plane, there are N red points and N blue points. The coordina ...

  6. HDU 1507 Uncle Tom's Inherited Land*(二分图匹配)

    Uncle Tom's Inherited Land* Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  7. POJ 2195 Going Home (带权二分图匹配)

    POJ 2195 Going Home (带权二分图匹配) Description On a grid map there are n little men and n houses. In each ...

  8. 【POJ】1486:Sorting Slides【二分图关键边判定】

    Sorting Slides Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5390   Accepted: 2095 De ...

  9. POJ3020:Antenna Placement(二分图匹配)

    Antnna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11093   Accepted: 5459 ...

随机推荐

  1. 链表--笔记--数据结构(C++版)王红梅--自我思路整理与梳理

    看到这篇文的很多人大概都知道链表是个什么玩意了.简单说就是一个又一个的指针,指针之间用指针连接起来. 本文的阅读   适合有c++基础的人群 以下: 这叫做一个结点. 这就是一个链表.我们主要使用的是 ...

  2. 使用Python基于OpenCV和Tesseract的OCR

    OCR OCR(Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别方法将形 ...

  3. Java设计模式七种写法

    懒汉模式-线程不安全 public class Singleton { private static Singleton instance; private Singleton (){ } publi ...

  4. LCT做题笔记

    最近几天打算认真复习LCT,毕竟以前只会板子.正好也可以学点新的用法,这里就用来写做题笔记吧.这个分类比较混乱,主要看感觉,不一定对: 维护森林的LCT 就是最普通,最一般那种的LCT啦.这类题目往往 ...

  5. (转)Redis持久化的几种方式

    radis持久化的几种方式 1.前言 Redis是一种高级key-value数据库.它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富.有字符串,链表,集 合和有序集合.支持在服 ...

  6. O020、理解 Glance

    参考https://www.cnblogs.com/CloudMan6/p/5384923.html   OpenStack 由 Glance 提供 Image 服务.   理解 Glance    ...

  7. js 获取当前月份 第一天和最后一天

    js 获取当前月份 第一天和最后一天 var now = new Date(); //当前日期 var nowMonth = now.getMonth(); //当前月 var nowYear = n ...

  8. a标签的download属性

    a标签加上downlaod属性后,就可完成对href属性链接文件的下载,但仅仅是限于同源文件,如果是非同源,download属性会失效. 无download属性的时候,a标签的默认行为是链接跳转进行预 ...

  9. Android系统修改之葡萄牙沃达丰One Net服务问题处理

    客户反馈的葡萄牙沃达丰的OneNet服务问题 Vodafone Portugal have a service (One Net) for enterprise customers that used ...

  10. TableView 键盘弹起冲突

    1.TableView 上cell 带有 TextField,如果 是Plain 形式的TableView ,并且设置SectionHeader的 取消粘滞效果 会导致键盘弹起,页面不能正常 上移 问 ...