zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    远程网络时间同步在分布式测控与实时仿真系统应用
    GPS对时装置(北斗卫星同步时钟)应用市场调研分析
    时间同步服务器(NTP时钟同步服务器)如何正确的选购?
    NTP授时服务器(卫星同步时钟)与物联网十大应用
    App 自动化环境搭建(基于 Appium)
    let var作用域
    vue methods和computed效率比较
    vue computed
    vue computed
    vue v-bind:style
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11383119.html
Copyright © 2011-2022 走看看