[题解]UOJ#41 矩阵变换

传送门

分析

先随便选

\(p[i][j]\)表示\(j\)这个数在第\(i\)行的位置,考虑不合法的情况:

假设第i行选择的数为\(x\),第\(j\)行选择的为\(y\),且\(p[i][x]<p[j][x]<p[j][y]\),那么在第\(p[j][x]\)列就会有两个\(x\)出现,不满足条件。

那么,我们最终的目标就是使得上述情况不存在

可以转化成稳定婚姻问题:

  • 对于每一行,优先去选在左边的
  • 对于每一个数,优先匹配\(p[i][x]\)大的\(i\)

代码

#include<bits/stdc++.h>
#define rep(X,A,B) for(int X=A;X<=B;X++)
#define tep(X,A,B) for(int X=A;X>=B;X--)
#define LL long long
const int N=210;
using namespace std;

int n,m,chk;
int ans[N],vis[N],p[N][N],a[N][N];
queue<int>Q;

void READ(){
	scanf("%d%d",&n,&m);
	int x=0;
	rep(i,1,n){
		rep(j,1,m){
			scanf("%d",&x);
			if(x)p[i][x]=j;
			a[i][j]=x;
		}
	}
}

void SOLVE(){
	rep(i,1,n)ans[i]=vis[i]=0,Q.push(i);
	while(!Q.empty()){
		int x=Q.front();Q.pop();
		rep(o,1,m){
			int i=a[x][o];
			if(!i)continue;
			if(!vis[i]||(vis[i]&&p[x][i]>p[vis[i]][i])){
				if(vis[i]){
					Q.push(vis[i]);
					ans[vis[i]]=0;
				}
				vis[i]=x;
				ans[x]=i;
				break;
			}
		}
	}
	int now=1;
	rep(i,1,n)if(!ans[i])now=0;
	if(now){
		rep(i,1,n)printf("%d ",ans[i]);
		printf("\n");
	}
	else printf("\\(^o^)/\n");
}

int CHK(){
	rep(i,1,n){
		if(!ans[i])return 0;
		int now=0;
		rep(j,1,m){
			if(a[i][j]==ans[i])now=a[i][j];
			if(now)a[i][j]=now;
		}
	}
	rep(j,1,m){
		rep(i,1,n)vis[i]=0;
		rep(i,1,n)vis[a[i][j]]++;
		rep(i,1,n)if(vis[i]>1)return 0;
	}
	return 1;
}

void SSOLVE(){
	READ();
	SOLVE();
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--)SSOLVE();
	return 0;
}
posted @ 2019-12-13 13:48  硫氯  阅读(194)  评论(0编辑  收藏  举报