UOJ #41【清华集训2014】矩阵变换

Description

给出一个 $N$ 行 $M$ 列的矩阵$A$, 保证满足以下性质:

  • $M > N$。
  • 矩阵中每个数都是 $[0,N]$ 中的自然数。
  • 每行中, $[1,N]$ 中每个自然数都恰好出现一次。这意味着每行中 $0$ 恰好出现 $M-N$ 次。
  • 每列中,$[1,N]$ 中每个自然数至多出现一次。

现在我们要在每行中选取一个非零数,并把这个数之后的数赋值为这个数。我们希望保持上面的性质4,即每列中,$[1,N]$ 中每个自然数仍然至多出现一次。

Solution

发现对于题目要求对于每一行都匹配一个数

对于每一行,希望匹配到的数在行内的位置尽量靠前

对于每一个数,希望在匹配到的行中位置尽量靠后

可以用延迟接受算法

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int T,n,m,ma[205][405],pos[205][205],mx[205],my[205];
queue<int>q;
inline int read(){
    int w=0,f=1;
    char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
    return w*f;
}
bool GS(){
    memset(mx,0,sizeof(mx)),memset(my,0,sizeof(my));
    for(int i=1;i<=n;i++)q.push(i);
    while(q.size()){
        int u=q.front();
        q.pop();
        for(int i=1;i<=m;i++){
            int x=ma[u][i];
            if(!x)continue;
            if(!my[x]||my[x]&&pos[x][u]>pos[x][my[x]]){
                if(my[x])q.push(my[x]),mx[my[x]]=0;
                mx[u]=x,my[x]=u;
                break;
            }
        }
    }
    for(int i=1;i<=n;i++)if(!mx[i])return false;
    return true;
}
int main(){
    T=read();
    for(;T;T--){
        n=read(),m=read();
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
            ma[i][j]=read();
            if(ma[i][j])pos[ma[i][j]][i]=j;
        }
        if(GS()){
            for(int i=1;i<=n;i++)printf("%d ",mx[i]);
            putchar(10);
        }
        else puts("\(^o^)/");
    }
    return 0;
}
【清华集训2014】矩阵变换
原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14295790.html