「學習筆記」uoj #41 【清華集訓2014】矩陣變換
阿新 • • 發佈:2018-12-13
題解:有這樣一個演算法: 給定n個排列Ai和n個排列Bi,求一個排列p使得: 可以在時間內求出一組解。可以證明必定有解。 演算法大致是,初始將所有數字push進佇列。 對於隊首元素,嘗試沒有嘗試過的並且最小的。 如果沒有被選擇,則令並退出對的嘗試; 否則若,則令,並且將放進隊尾並退出對的嘗試; 否則對繼續嘗試下一個。 首先不難發現其演算法複雜度由於對於x的選擇越來越劣因此複雜度是。同時正確性略(大霧)。 在這個題中,對行和顏色考慮,每行按照從左到右偏愛顏色,顏色按照出現的列從右向左偏向行。 然後直接執行上述演算法即可。
#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;
}