居然给想出解法了。。。。
从题目中我们可以看出,每个数一定是尽量取列靠后的。
如果这样一行中出现了多个数怎么办?拿纸出来画一画可以发现我们因该保留靠前的那一个而把靠后的一个再向前一列取一下。
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define pb push_back
int g[205],rk[205][205],q[200*200+5];
int Case,n,m,x,i,j,l,r,t;
struct arr
{
int x,y;
bool operator <(const arr &a)const
{ return y<a.y; }
} tmp;
vector <arr> num[205];
int read(){
int ret=0;
char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9')
{ret=ret*10+ch-'0'; ch=getchar();}
return ret;
}
bool calc(){
memset(g,0,sizeof(g));
for (i=1;i<=n;i++)
q[i] = i;
for (l=1, r=n;l<=r;l++){
t = q[l];
while (!num[t].empty()){
tmp = num[t].back();
if (g[tmp.x]==0) {g[tmp.x]=t;break;}
if (rk[ tmp.x ][ g[tmp.x] ]>tmp.y)
{ q[++r]=g[tmp.x]; g[tmp.x]=t; break; }
num[t].pop_back();
}
if (num[t].empty()) break;
num[t].pop_back();
}
return 1;
}
int main(){
//freopen("3816.in","r",stdin);
//freopen("3816.out","w",stdout);
Case=read();
//scanf("%d",&Case);
while (Case--){
n=read(); m=read();
//scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) num[i].clear();
for (i=1;i<=n;i++)
for (j=1;j<=m;j++){
x=read();
//scanf("%d",&x);
if (x!=0){
num[x].pb( (arr){i,j} );
rk[i][x] = j;
}
}
for (i=1;i<=n;i++)
sort( num[i].begin(), num[i].end() );
if (!calc()) {puts("\(^o^)/");continue;}
for (i=1;i<n;i++) printf("%d ",g[i]);
printf("%d\n",g[n]);
}
return 0;
}