题意:
有一个n*m的矩阵,现在让你构造长度为m的排列,使得所有行的数按照这个排序之后字典序从上到下递增,若有多种解,输出字典序最小的一个。
题解:
一般字典序的题目的解法 是贪心,并且这道题贪心是可行的。对于每次选的话,我们不能
判断,需要快速判断每一列是否可行。使用一个数组表示当前有多少不允许范围内递减的数:
假设当前的列为12234,那么2-3在之后是不允许递减的,其它是允许递减的。所以对于每一次选择列之后,对于没有运算过的行,如果当前选择的列中第i行与第i+1行是递增的并且之前没有做过这个操作,我们将所有列都置为允许递减,也就是如果别的列第i个与第i+1个是递减的,那么消去这个影响。由于每一行最多被消去影响一次,总时间复杂度是可以保证的。
有点拗口。。
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+5;
int mp[N][N],desc[N],ans[N];
bool vis[N],ers[N];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(vis,0,sizeof(vis));
memset(ers,0,sizeof(ers));
memset(desc,0,sizeof(desc));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]),desc[j]+=mp[i][j]<mp[i-1][j];
int f=0;
for(int t=1;t<=m;t++)
{
int p=1;
for(;p<=m;p++)
{
if(vis[p])continue;
if(!desc[p])break;
}
if(p>m){f=1;break;}
ans[t]=p,vis[p]=1;
for(int i=1;i<n;i++)
{
if(ers[i]||mp[i][p]>=mp[i+1][p])continue;
for(int j=1;j<=m;j++)
{
if(vis[j])continue;
if(mp[i][j]>mp[i+1][j])desc[j]--;
ers[i]=1;
}
}
}
if(f)
{
printf("-1\n");
continue;
}
for(int i=1;i<=m;i++)
printf("%d%c",ans[i]," \n"[i==m]);
}
return 0;
}