【2018/08/29测试T2】【SDOJ 3728】表格

【题目】

题目描述:

给出一个表格,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

输出

2 3 1

【样例2】 

输入

2 2
1 2
2 1

输出

-1

备注:

【数据规模与约定】

对于 20% 的数据,满足 1 ≤ N ≤ 8,1 ≤ M ≤ 8。
对于 60% 的数据,满足 1 ≤ N × M ≤ 2 × 10^{3}
对于 100% 的数据,满足 1 ≤ N × M ≤ 10^{5}

【分析】

对于每一行,都从小到大排序,排在前面的就向排在后面的建边

由于数据中可能有多个数字相同的情况,我们要建一些虚点

比如说,如果某一行是 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;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/82181931