UOJ #41【清华集训2014】矩阵变换
Description
给出一个 $N$ 行 $M$ 列的矩阵$A$, 保证满足以下性质:
- $M > N$。
- 矩阵中每个数都是 $[0,N]$ 中的自然数。
- 每行中, $[1,N]$ 中每个自然数都恰好出现一次。这意味着每行中 $0$ 恰好出现 $M-N$ 次。
- 每列中,$[1,N]$ 中每个自然数至多出现一次。
现在我们要在每行中选取一个非零数,并把这个数之后的数赋值为这个数。我们希望保持上面的性质4,即每列中,$[1,N]$ 中每个自然数仍然至多出现一次。
Solution
发现对于题目要求对于每一行都匹配一个数
对于每一行,希望匹配到的数在行内的位置尽量靠前
对于每一个数,希望在匹配到的行中位置尽量靠后
可以用延迟接受算法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }