【CTS2023】琪露诺的符卡交换

【CTS2023】琪露诺的符卡交换

Description

受异变的影响,琪露诺发现封印了自己能力的卡片正在幻想乡中流通。

琪露诺调查之后,发现一共有 \(n\) 种不同的卡片,每种卡片的数量总共恰好是 \(n\) 张,有 \(n\) 个人购买了这些卡片,每个人都恰好买了 \(n\) 张卡片,并且可能会买到相同种类的卡片。

但是琪露诺想要让每个人都正好持有 \(n\) 种卡片,于是她把这 \(n\) 个人聚集在一起,想要通过卡片交换的形式达成她的目的。

琪露诺每次会选择两个人持有的某张卡片进行交换,直到每个人都正好持有 \(n\) 种卡片为止。

由于每次交换都会减少卡片上的魔力,所以琪露诺想要每张卡片最多被交换一次。

但是她对如何进行交换犯了难,于是她转而寻求你的帮助。

你需要告诉她交换的过程,或者告诉她不存在这样的方案。

Input

第一行一个正整数 \(T\),表示数据组数。

对于每组数据,第一行一个正整数 \(n\),含义如题所示。

接下来 \(n\) 行,每行输入 \(n\) 个正整数,其中第 \(i\) 行的第 \(j\) 个正整数表示第 \(i\) 个人持有的第 \(j\) 张卡片的种类。

Output

对于每组数据,如果不存在能够让每个人都持有 \(n\) 种卡片的方案,输出一行 \(-1\)

否则首先输出一行一个正整数 \(m\),表示交换次数。

接下来 \(m\) 行,每行输出四个正整数 \(a,b,c,d\),表示第 \(a\) 个人的第 \(b\) 张卡片,与第 \(c\) 个人的第 \(d\) 张卡片进行一次交换。

注意你需要保证不存在某张卡片被交换了两次,并且交换结束后每个人都正好持有 \(n\) 种卡片。

Sample Input

2
3
1 2 2
2 3 3
3 1 1
3
1 2 3
2 3 1
3 2 1

Sample Output

2
1 3 3 1
2 3 3 2
0

Data Constraint

对于所有数据,满足 \(\sum\limits_{i=1}^{T}n_{i} \leq 200\)

Solution

考虑sub2

可以把每个人多出来的那张卡放到最后,然后你会惊奇地发现,转置就满足了要求

所以问题转化为每个人先调整手中的卡牌顺序,使得转置后每个数在每列中都出现过

于是逐列确定,每个人向卡牌颜色连边,然后跑最大匹配

根据霍尔定理一定有解,证明也不难

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 210

int T,n,a[N][N],w[N],vis[N],num[N];
vector<int>e[N],pos[N][N];

bool dfs(int x){
	for(auto y:e[x])if(!vis[y]){
		vis[y]=1;
		if(!w[y]||dfs(w[y])){
			w[y]=x;
			return 1;
		}
	}
	return 0;
}

int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		F(i,1,n) F(j,1,n){
			int x;
			scanf("%d",&x);
			e[i].push_back(x);
			pos[i][x].push_back(j);
		}
		F(i,1,n){
			F(j,1,n)w[j]=0;
			F(j,1,n){
				F(k,1,n)vis[k]=0;
				dfs(j);
			}
			F(j,1,n)num[w[j]]=j;
			F(j,1,n){
				int x=num[j];
				a[j][i]=pos[j][x].back();
				pos[j][x].pop_back();
				e[j].erase(find(e[j].begin(),e[j].end(),x));
			}
		}
		printf("%d\n",n*(n-1)/2);
		F(i,1,n) F(j,i+1,n){
			printf("%d %d %d %d\n",i,a[i][j],j,a[j][i]);
		}
	}
	return 0;
}
posted @ 2023-03-06 19:08  冰雾  阅读(76)  评论(0编辑  收藏  举报