• 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
    ",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
    ",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)
    ",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;
    }
    
  • 相关阅读:
    hikariCP性能调优
    Mysql 8.0 my.ini 系统变量设置Server System Variable Reference
    MySQL性能测试 : 新的InnoDB Double Write Buffermysql .dblwr
    MySQL MyISAM/InnoDB高并发优化经验
    解决NAVICAT 无法连接MYSQL8.0.12_可视化工具无法连接 MYSQL 8.0
    quartz 节点争抢Job 问题算法
    认识Flink中的Window
    多个用户同时update同一张表中的同一条记录会导致死锁吗?MySQL数据库?
    java.util.Base64 基本使用
    解决JDK1.8 编译时提示 程序包com.sun.image.codec.jpeg不存在的问题
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11383119.html
Copyright © 2020-2023  润新知