题目链接

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. 【计算机网络】-介质访问控制子层-无线LAN

    [计算机网络]-介质访问控制子层-无线LAN 802.11体系结构和协议栈 802.11网络使用模式: 有架构模式(Infrastructure mode) 无线客户端连接接入点AP,叫做有架构模式 ...

  2. Mysql之SQL随笔

    1.创建数据库 create database if not exists shop default character set utf8mb4 default collate utf8mb4_uni ...

  3. React 中的函数式思想

    函数式编程简要概念 函数式编程中一个核心概念之一就是纯函数,如果一个函数满足一下几个条件,就可以认为这个函数是纯函数了: 它是一个函数(废话): 当给定相同的输入(函数的参数)的时候,总是有相同的输出 ...

  4. java实现的LinkedLilst

    package javabean.adt.List; import java.util.ConcurrentModificationException; import java.util.Iterat ...

  5. 剑指offer-数组中重复的数字-数组-python

    题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...

  6. nodejs---crypto模块MD5签名

    1.MD5是一种常用的哈希算法,用于给任意数据一个“签名”.这个签名通常用一个十六进制的字符串表示: /*md5签名*/ /*引入crypto模块*/ const crypto = require(' ...

  7. php 中php-fpm工作原理

    1.CGI 是服务器与后台语言交互的协议,有了这个协议,开发者可以使用任何语言处理服务器转发过来的请求,动态地生成内容, 保证了传递过来的数据是标准格式的(规定了以什么样的格式传哪些数据(URL.查询 ...

  8. 从命令行运行postman脚本

    为什么要在命令行中运行 可以在无UI界面的服务器上运行 可以在持续集成系统上运行 运行准备 导出collection 安装nodejs和npm(或cnpm) 安装Newman 运行及生成测试报告支持4 ...

  9. 获取图书isbn信息 共享图书开发 图书信息接口开发过程中的心得体会

    最近做一个图书共享的项目,需要用户扫一扫书籍后面的一维码,获取到书籍的isbn号码,然后通过这个isbn号码能够直接获取到这本书的名字.简介.价格.图片等信息. 于是百度搜了下,之前很多的豆瓣的接口, ...

  10. Ubuntu 部署Python开发环境

    一.开发环境包安装 sudo apt-get install git-core sudo apt-get install libxml2-dev sudo apt-get install libxsl ...