表格
给出一个表格,N 行 M 列,每个格子有一个整数,有些格子是空的。现在需要你来做出一些调整,使得每行都是非降序的。这个调整只能是整列的移动。
【输入】
第一行两个正整数 N 和 M。
接下来 N 行,每行 M 个整数,-1 表示这个格子是空的,其他的整数都在 [0, 10^9]范围,表示格子的数字。
【输出】
若无解,输出 -1;
否则输出任意一个解,即一行 M 个正整数 p1, p2, · · · , pm,表示可以把初始表格的 pi 列,放在新表格的第 i 列,以得到一个合法的表格。
【样例输入1】
3 3
-1 -1 -1
2 1 2
2 -1 1
【样例输出1】
2 3 1
【样例输入2】
2 2
1 2
2 1
【样例输出2】
-1
对于 20% 的数据,满足 1 ≤ N ≤ 8,1 ≤ M ≤ 8。
对于 60% 的数据,满足 1 ≤ N × M ≤ 2 × 10^3。
对于 100% 的数据,满足 1 ≤ N × M ≤ 10^5。
分析
莫名其妙的爆搜居然卡爆了spj???我也很无奈 ldx大佬觉得这题正解很好想???我怎么一点也看不出来。。。哎,还是太弱了
由于最后排出来的每一行都是非降序的,意思就是说是升序的(不过相邻的可以相等)。那么就有一定的顺序了,某一列必须在某一列之前,诸如此类。我们就可以联想到拓扑排序,然后建个图,跑一遍Kahn,就出来答案了。只是要注意建图的时候,我们可以O(n)解决,先将这一行的数排一个序,然后前后两两连边,遇到相同的数的时候我们就建一个虚点,把每一个数都连向虚点,下一次再从虚点连出去,就保证了O(n)的复杂度(n^2 的做法就是每两个数连一条边)
无解的情况就是建完图后出现环,之前傻逼的在想如何快速判环(过路大佬麻烦指教一下),后面才发现直接最后看答案有没有m个即可
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<queue>
#define in read()
#define ll long long
#define N 100009
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-48;ch=getchar();}
return f==1?res:-res;
}
int n,m,nxt[4*N],head[N],to[4*N],du[N],tot=0;
int ans[N];
queue<int > q;
struct node{int pos,v;}a[N];
inline bool cmp(const node &a,const node &b){return a.v<b.v;}
inline void add(int x,int y){nxt[++tot]=head[x];head[x]=tot;to[tot]=y;}
int main(){
n=in;m=in;
int i,j,k,top=m;
for(i=1;i<=n;++i){
for(j=1;j<=m;++j)
{ a[j].v=in;a[j].pos=j; }
sort(a+1,a+m+1,cmp);
int l=1,r=1;
k=-1;
while(r<=m){
while(r<=m&&a[l].v==a[r].v) r++;//第一个不等于a[l].v的位置
if(a[l].v==-1){
l=r;continue;///////////////
}
if(k!=-1)
for(int p=l;p<r;++p) add(k,a[p].pos),++du[a[p].pos];//从上一个虚点连向当前点
k=++top;
for(int p=l;p<r;++p) add(a[p].pos,k),++du[k];//新建一个虚点并从当前点连出去
l=r;//别忘了更新l
}
}
int num=0;
for(i=1;i<=top;++i)///////////////
if(!du[i]) q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
if(u<=m){
ans[++num]=u;
}//只有当现在的这个点不是我们搞出来的虚点时才能记录进答案
for(int e=head[u];e;e=nxt[e]){
int v=to[e];
--du[v];
if(!du[v]) q.push(v);
}
}
if(num!=m) printf("-1");
else {
for(i=1;i<=m;++i)
printf("%d ",ans[i]);
}
return 0;
}