首页 > 其他分享 >[ABC317G] Rearranging 题解

[ABC317G] Rearranging 题解

时间:2023-08-27 13:55:05浏览次数:41  
标签:二分 head idx int 题解 ABC317G aligned Rearranging

取自我的洛谷博客:https://www.luogu.com.cn/blog/SunnyYuan/solution-at-abc317-g

借鉴了官方题解思路。

思路

首先我们要建立一个二分图。

对于输入的 \(a_{i, j}\),我们可以连接 左侧的 \(i\) 和 右侧的 \(a_{i, j}\)。

比如样例 \(1\):

注意:左边的 \(1, 2, 3\) 和 右边的 \(1, 2, 3\) 完全不一样,一个是行数,一个是数字。

  1. 那我们现在找出一组二分图的最大匹配,那么就代表对于固定的一列,第 \(i\) 行的数字就可以确定了。

    比如上图中橙色的边,它们就是一组二分图的最大匹配,我们可以通过其知道对于一列,可以这么填:

\[\begin{aligned} 1\\ 3\\ 2\\ \end{aligned} \]

  1. 我们将已经匹配的边删去,然后再跑下一次的二分图,构建下一列的数字。就这样执行 \(m\) 遍,就可以做出答案。

    可以得到最大匹配,然后构建出这一列数字:

\[\begin{aligned} 1\\ 2\\ 3\\ \end{aligned} \]

  1. 最后将这么多列数字按任意顺序输出就可以了。

\[\begin{aligned} \text{1 1}\\ \text{2 3}\\ \text{3 2}\\ \end{aligned} \]

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 210, M = 40010, INF = 0x3f3f3f3f;

struct edge {
	int to, next, w;
} e[M];

int head[N], idx = 1;

void add(int u, int v, int w) {
	idx++, e[idx].to = v, e[idx].next = head[u], e[idx].w = w, head[u] = idx;
	idx++, e[idx].to = u, e[idx].next = head[v], e[idx].w = 0, head[v] = idx;
}

int S, T;
int n, m;
int q[N], hh, tt;
int d[N];
int ans[N][N];

bool bfs() {
	memset(d, 0, sizeof(d));
	hh = tt = 0;
	q[0] = S;
	d[S] = 1;

	while (hh <= tt) {
		int u = q[hh++];

		for (int i = head[u]; i; i = e[i].next) {
			int to = e[i].to;
			if ((!d[to]) && e[i].w) {
				d[to] = d[u] + 1;
				q[++tt] = to;
			}
		}
	}

	return d[T];
}

int dinic(int u, int limit) {
	if (u == T) return limit;

	int rest = limit;
	for (int i = head[u]; i && rest; i = e[i].next) {
		int to = e[i].to;
		if (d[to] == d[u] + 1 && e[i].w) {
			int k = dinic(to, min(rest, e[i].w));
			if (!k) d[to] = INF;
			rest -= k;
			e[i].w -= k;
			e[i ^ 1].w += k;
		}
	}
	return limit - rest;
}

int maxflow() {
	int ans = 0, flow = 0;
	while (bfs()) while (flow = dinic(S, INF)) ans += flow;
	return ans;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin >> n >> m;
	S = 0, T = n << 1 | 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			int x;
			cin >> x;
			add(i, x + n, 1);
		}
	}
	int tmp = idx;
	for (int i = 1; i <= n; i++) add(S, i, 1), add(i + n, T, 1);

	for (int j = 1; j <= m; j++) {
		if (maxflow() != n) {
			cout << "No\n";
			return 0;
		}
		for (int i = 3; i <= tmp; i += 2) if (e[i].w == 1) {
			int u = e[i].to, v = e[i ^ 1].to;
			ans[u][j] = v - n;
			e[i].w = e[i ^ 1].w = 0;
		}
		for (int i = tmp + 2; i <= idx; i += 2) {
			if (e[i].w == 1) {
				e[i ^ 1].w = 1;
				e[i].w = 0;
			}
		}
	}
	cout << "Yes\n";
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cout << ans[i][j] << ' ';
		}
		cout << '\n';
	}
	return 0;
}

标签:二分,head,idx,int,题解,ABC317G,aligned,Rearranging
From: https://www.cnblogs.com/Yuan-Jiawei/p/17660224.html

相关文章

  • 「TAOI-2」Ciallo~(∠・ω< )⌒★ 题解
    「TAOI-2」Ciallo~(∠・ω<)⌒★题解不难发现,答案可以分成两种:整段的中间删一点,两端凑一起的考虑分开计算贡献。如果\(s\)中存在子串等于\(t\),那么自然,可以删左边的任何一段,或者右边的任何一段。不妨设子串开始的位置为\(i\),于是其贡献为\((1+2+\cdots+i......
  • YACS 2023年8月月赛 甲组 T2 直线整点 题解
    简单题,先二分出直线上$x$最小的点使得这个点在矩形内。然后不断跳,直到遇到整点。(实际上要用扩欧,但初测能过于是就偷个懒没写) 接着不断跳直到不符合条件。先$\sqrt{V}$个跳一下,跳完后再一个一个跳就不用写二分了多好。代码:#include<iostream>#defineintlonglongusi......
  • UVA908[Re-connecting Computer Sites]题解
    原题1.题意分析题意就是给你很多组数,对于每组数,有三组小数据。第一组小数据先输入一个n表示顶点数,然后再输入n-1条边表示初始边数。其它组小数据先输入一个数k,表示增加的边的数量,然后再输入k条边,表示增加的边。在输入第二组小数据时,要先把边清空,重新输入,但是边的数量不变。2.做......
  • 题解:城市
    题目链接你说得对,但是不如换根。换根是由原先的树形DP简单变换而来,故事发生在这道叫做《城市》的题目中,在这里你妄图求解每个点到树中其它所有节点的距离,即\(f_i=\sum_{j=1}^ndis_{i\toj}\)。可以一次dfs求解出\(f_{root}\),然后我们发现走过一条边\((u,v,w)\)会使......
  • LGR-156-Div.3 题解
    LGR-156-Div.3题解洛谷网校8月普及组月赛I&MXOIRound1&飞熊杯#2第一次AK一个比赛!而且排名这么靠前!!!T1宝箱题目链接思路注意到答案有两种情况。1.从原点走到\(a\),再从\(a\)走到\(b\),2.从原点走到\(b\),再从\(b\)走到\(a\)。取一个最小值即可。代码int......
  • react-pdf在部分iOS手机上加载pdf失败问题解决
    最近项目快结束了,测试提了一个bug,iOS手机上加载pdf一直在转圈,加载不出来内容。看到这个bug,在电脑上和安卓手机上没有问题,iOS手机中打开确实又问题,初步确定为app问题。我们的项目是集成在客户的app里的,可能是app内的WebView和Safari有一些差异导致的问题。首先直接在iOS手机上用a......
  • 力扣-2. 两数相加(C++题解)
    题目链接:https://leetcode.cn/problems/add-two-numbers/description/给你两个 非空的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字0之......
  • 关于自建Rustdesk 远程桌面服务器的公网访问:无法连接中继服务器的问题解决方法
    自建服务器位于内网时,内网客户端ID/中继的地址通常写成内网IP,外网客户端一般会用公网IP进行端口映射,但这样设置出现外网客户端无法连接中继服务器,但内网客户端使用正常的现象。经过半天的排查分析,当内网和外网填写的自定义服务器地址时,rust服务器无法识别出需要使用nat包的地址,默......
  • P1848 Bookshelf G 题解
    这是本蒟蒻写的第一篇题解(写不好请指出)很明显他是一道dp题,因为第i本书放哪里只跟前i-1本树的放法有关系。我们可以是定义f[i][j]表示放了i本书,最后一层书架是以第j本书开始的。那么有动态转移方程:\(f[i][i]=min(f[i-1][j])+hi,w[j]+...+w[i-1]<=L\)\(f[i][j]=f[i-1][j]+max(0......
  • 力扣-228. 汇总区间(C++题解)
    题目链接:https://leetcode.cn/problems/summary-ranges/description/给定一个 无重复元素的 有序整数数组\(nums\)。返回恰好覆盖数组中所有数字的最小有序区间范围列表 。也就是说,\(nums\)的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于\(......