「学习笔记」【清华集训2014】uoj #41 矩阵变换 - 稳定婚姻算法 - 学习笔记

题解:有这样一个算法:
给定n个排列Ai和n个排列Bi,求一个排列p使得:
∀ i , j ∈ [ 1 , n ] , j ≠ p i , A i , p i &lt; A i , j ∨ B k ∣ p k = j , j &lt; B i , j \forall i,j\in[1,n],j\neq p_i,A_{i,p_i}&lt;A_{i,j}\vee B_{k|_{p_k=j},j}&lt;B_{i,j} i,j[1,n],j̸=pi,Ai,pi<Ai,jBkpk=j,j<Bi,j
可以在 O ( n 2 ) O\left(n^2\right) O(n2)时间内求出一组解。可以证明必定有解。
算法大致是,初始将所有数字push进队列。
对于队首元素 x x x,尝试 x x x没有尝试过的并且 A x , y A_{x,y} Ax,y最小的 y y y
如果 y y y没有被选择,则令 p x = y p_x=y px=y并退出对 x x x的尝试;
否则若 B z ∣ p z = y , y &gt; B x , y B_{z|_{p_z=y},y}&gt;B_{x,y} Bzpz=y,y>Bx,y,则令 p x = y p_x=y px=y,并且将 z ∣ p z = y z|_{p_z=y} zpz=y放进队尾并退出对 x x x的尝试;
否则对 x x x继续尝试下一个 y y y
首先不难发现其算法复杂度由于对于x的选择越来越劣因此复杂度是 O ( n 2 ) O\left(n^2\right) O(n2)。同时正确性略(大雾)。
在这个题中,对行和颜色考虑,每行按照从左到右偏爱颜色,颜色按照出现的列从右向左偏向行。
然后直接运行上述算法即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define N 210
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int pfx[N][N],pfy[N][N],a[N][N<<1],cntx[N],pt[N];
queue<int> q;int p[N],fr[N],vis[N],cnty[N];
int main()
{
	for(int T=inn();T;T--)
	{
		int n=inn(),m=inn(),c;memset(cntx,0,sizeof(int)*(n+1));
		rep(i,1,n) cnty[i]=n;memset(pt,0,sizeof(int)*(n+1));
		memset(vis,0,sizeof(int)*(n+1));rep(i,1,n) rep(j,1,m) a[i][j]=inn();
		rep(i,1,n) rep(j,1,m) if((c=a[i][j])) pfx[i][++cntx[i]]=c;
		rep(j,1,m) rep(i,1,n) if((c=a[i][j])) pfy[c][i]=cnty[c]--;
		while(!q.empty()) q.pop();rep(i,1,n) q.push(i);
		for(int x,y;!q.empty();q.pop())
			for(x=q.front(),p[x]=0;!p[x];)
				if(!vis[y=pfx[x][++pt[x]]]) p[x]=y,fr[y]=x,vis[y]=1;
				else if(pfy[y][x]<pfy[y][fr[y]]) p[x]=y,q.push(fr[y]),fr[y]=x;
		rep(i,1,n) printf("%d ",p[i]);printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值