【题目】
题目描述:
给出一个表格,N 行 M 列,每个格子有一个整数,有些格子是空的。现在需要你来做出一些调整,使得每行都是非降序的。这个调整只能是整列的移动。
输入格式:
第一行两个正整数 N 和 M。
接下来 N 行,每行 M 个整数,-1 表示这个格子是空的,其他的整数都在 [ 0 , ] 范围,表示格子的数字。
输出格式:
若无解,输出 -1;否则输出任意一个解,即一行 M 个正整数 p1, p2, · · · , pm,表示可以把初始表格的 pi 列,放在新表格的第 i 列,以得到一个合法的表格。
样例数据:
【样例1】
输入
3 3 -1 -1 -1 2 1 2 2 -1 1
输出
2 3 1
【样例2】
输入
2 2 1 2 2 1
输出
-1
备注:
【数据规模与约定】
对于 20% 的数据,满足 1 ≤ N ≤ 8,1 ≤ M ≤ 8。
对于 60% 的数据,满足 1 ≤ N × M ≤ 2 × 。
对于 100% 的数据,满足 1 ≤ N × M ≤ 。
【分析】
对于每一行,都从小到大排序,排在前面的就向排在后面的建边
由于数据中可能有多个数字相同的情况,我们要建一些虚点
比如说,如果某一行是 2 2 3 3,那么我们建立一个虚点,2 2 向虚点连边,虚点向 3 3 连边
有很多个数字相同的话我们就建很多个虚点就行了
这样,跑一遍拓扑排序,如果有负环就无解,否则就有解
【代码】
#include<stack>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500005
using namespace std;
stack<int>sta;
struct node
{
int id,num;
}a[N];
int t,v[N],next[N];
int du[N],ans[N],first[N];
bool comp(const node &p,const node &q)
{
return p.num<q.num;
}
void add(int x,int y)
{
t++;
next[t]=first[x];
first[x]=t;
v[t]=y;
}
int main()
{
// freopen("table.in","r",stdin);
// freopen("table.out","w",stdout);
int n,m,i,j,l,r,x,point,sum=0;
scanf("%d%d",&n,&m);
point=m;
for(i=1;i<=n;++i)
{
for(j=1;j<=m;++j)
{
a[j].id=j;
scanf("%d",&a[j].num);
}
sort(a+1,a+m+1,comp);
for(l=1,r=1,x=-1;l<=m;l=r)
{
while(r<=m&&a[r].num==a[l].num) ++r;
if(a[l].num==-1) continue;
if(x!=-1)
for(j=l;j<r;++j)
add(x,a[j].id),du[a[j].id]++;
x=++point;
for(j=l;j<r;++j)
add(a[j].id,x),du[x]++;
}
}
for(i=1;i<=point;++i)
if(!du[i])
sta.push(i);
while(!sta.empty())
{
x=sta.top();
sta.pop();
if(x<=m) ans[++sum]=x;
for(i=first[x];i;i=next[i])
{
du[v[i]]--;
if(!du[v[i]])
sta.push(v[i]);
}
}
if(sum!=m)
printf("-1");
else
{
for(i=1;i<=m;++i)
printf("%d ",ans[i]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}