题目链接

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. Ubuntu基本操作(博主想上传图片给服务器的一些命令)

    1.将当前目录下的文件移动至指定文件夹,这里用移动至网站的根目录做示范 sudo mv bamboo.jpg /val/www/html mv bamboo.jpg /val/www/html 2.进 ...

  2. CE修改器使用教程 [入门篇]

    Cheat Engine 一般简称CE,是一个开放源代码的作弊软件,其功能包括:内存扫描.十六进制编辑器.调试工具,Cheat Engine 自身附带了外挂制作工具,可以用它直接生成外挂工具,CE可以 ...

  3. The Party and Sweets CodeForces - 1159C (拓排)

    优化连边然后拓排. #include <iostream> #include <sstream> #include <algorithm> #include < ...

  4. oa_mvc_easyui_后台布局(3)

    1.新建HomeController控制器,并创建视图,后台的主页 2.easyUI的引用: <link href="~/Content/default/easyui.css" ...

  5. springboot(二十)-配置文件 bootstrap和application区别

    用过 Spring Boot 的都知道在 Spring Boot 中有以下两种配置文件 bootstrap (.yml 或者 .properties) application (.yml 或者 .pr ...

  6. springboot(十六)-swagger2

    SpringBoot整合Swagger2 相信各位在公司写API文档数量应该不少,当然如果你还处在自己一个人开发前后台的年代,当我没说,如今为了前后台更好的对接,还是为了以后交接方便,都有要求写API ...

  7. SuperMap webgl对接iportal托管的三维服务

    在webgl中对接iportal加密的三维服务时,需要提前注册key值.Cesium.Credential.CREDENTIAL = new Cesium.Credential("你的key ...

  8. vue高亮一级、二级导航

    使用vue开发过程中有的项目会存在多级导航的情况,如下图,这种就存在了两层,那么该如何高亮一级导航,又该如何高亮二级导航这就是今天我要记录的内容. 1.高亮一级导航很简单,代码如下: // 点击一级导 ...

  9. mock.js 模拟数据

    1. 劫持请求,返回模拟数据: 用于前后台对接前数据模拟 相比于静态json文件而言:代码完成后不必修改源文件对应的接口调用.可模拟增删改查 2.实例代码 <!doctype html> ...

  10. Elasticsearch 7.4.0官方文档操作

    官方文档地址 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html 1.0.0 设置Elasticsea ...