[题解]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;
}
上一篇:【UOJ 888】四轮车


下一篇:【UOJ#495】新年的促销