AtCoder AGC037D Sorting a Grid (二分图匹配)
题目链接
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 (二分图匹配)的更多相关文章
- Sorting Slides(二分图匹配——确定唯一匹配边)
题目描述: Professor Clumsey is going to give an important talk this afternoon. Unfortunately, he is not ...
- POJ 1486 Sorting Slides【二分图匹配】
题目大意:有n张幻灯片和n个数字,幻灯片放置有重叠,每个数字隶属于一个幻灯片,现在问你能够确定多少数字一定属于某个幻灯片 思路:上次刷过二分图的必须点后这题思路就显然了 做一次二分匹配后将当前匹配的边 ...
- POJ 1486 Sorting Slides(二分图匹配)
[题目链接] http://poj.org/problem?id=1486 [题目大意] 给出每张幻灯片的上下左右坐标,每张幻灯片的页码一定标在这张幻灯片上, 现在问你有没有办法唯一鉴别出一些幻灯片 ...
- POJ 1486 Sorting Slides(二分图完全匹配必须边)题解
题意:给你n张照片的范围,n个点的坐标,问你能唯一确定那几个点属于那几张照片,例如样例中4唯一属于A,2唯一属于C,1唯一属于B,3唯一属于C 思路:进行二分图完全匹配,怎么判断唯一属于?匹配完之后删 ...
- 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 ...
- 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 ...
- POJ 2195 Going Home (带权二分图匹配)
POJ 2195 Going Home (带权二分图匹配) Description On a grid map there are n little men and n houses. In each ...
- 【POJ】1486:Sorting Slides【二分图关键边判定】
Sorting Slides Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 5390 Accepted: 2095 De ...
- POJ3020:Antenna Placement(二分图匹配)
Antnna Placement Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11093 Accepted: 5459 ...
随机推荐
- 用Java实现对英文版《飘》的文件读取与写入操作
从文件读入<飘>的英文版,并将结果输出到文件中 要求一: 实现对英文版<飘>的字母出现次数统计 package File; import java.io.FileInputSt ...
- Docker学习1
命名空间(Namesaoces):Linux内核提供的一种对进程资源隔离的机制,例如网络.进程.挂载点等资源. 控制组(CGroups):Linux内核提供的一种限制进程资源的机制:例如CPU.内存等 ...
- Linux-1.1root初始密码设置,切换root用户
Ubuntu安装好后,root密码需要自己设置 root初始密码设置 sudo passwd root 权限不够时,切换root su 回车后输入密码 exit 退出登录的账户
- python网络爬虫(7)爬取静态数据详解
目的 爬取http://seputu.com/数据并存储csv文件 导入库 lxml用于解析解析网页HTML等源码,提取数据.一些参考:https://www.cnblogs.com/zhangxin ...
- button标签与input type=button标签使用的差异
button标签和input type=button标签都是html文档中用来表示按钮属性的元素,不过他们在布局和实际使用功能中存在一些差异. 下面将项目中遇到的一些总结如下: 1.属性和布局差异. ...
- 06 Python之列表和元组
1. 什么是列表 定义: 能装对象的对象 在python中使用[]来描述列表, 内部元素用逗号隔开. 对数据类型没有要求 列表存在索引和切片. 和字符串是一样的. 2. 相关的增删改查操作 添加: 1 ...
- CSS行高——line-height 垂直居中等问题
CSS行高——line-height 初入前端的时候觉得CSS知道display.position.float就可以在布局上游刃有余了,随着以后工作问题层出不穷,才逐渐了解到CSS并不是几个sty ...
- php连接阿里云mysql
1.开启Mysql远程访问端口 现在服务器控制台,安全组那边开启3306端口 2.修改Mysql配置文件 vim /etc/mysql/mysql.conf.d/mysqld.cnf,找到bind-a ...
- redis和mongodb面试题(一)
● 请你回答一下mongodb和redis的区别 参考回答: 内存管理机制上:Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据.MongoDB 数据存在内 ...
- Delphi 内部过程和函数