思路:如果要求字典序最小。 左侧从后向前遍历,每个点枚举边的顺序为从小到大。
如果要求字典序最大。左侧从后向前遍历,每个点枚举边的顺序为从大到小。
#include <bits/stdc++.h>
using namespace std;
const int maxm = 2000;
const int maxn = 2000;
int he[maxn],ver[10000],ne[10000],tot;
void init(int n){
for( int i = 0;i <= n;i++ ) he[i] = 0;
tot = 1;
}
void add( int x,int y ){
ver[++tot] = y;
ne[tot] = he[x];
he[x] = tot;
}
int vis[maxn],match[maxn];
bool dfs( int x ){
for( int cure = he[x];cure;cure = ne[cure] ){
int y = ver[cure];
if( !vis[y] ){
vis[y] = 1;
if( !match[y] || dfs( match[y] ) ){
match[y] = x;return true;
}
}
}
return false;
}
vector<int> ve[maxm];
int main(){
int T,n,m;
vector<int>pos[26];
char str1[maxm],str2[maxm];
scanf("%d",&T);
while(T--){
bool flag = true;
scanf("%d%d",&n,&m);
init(2*m+1);
for( int i = 0;i < 2*m+1;i++ ) match[i] =0,ve[i].clear();
for( int i = 1;i <= n;i++ ){
scanf("%s%s",str1,str2);
int len = strlen(str2);
for( int i = 0;i < 26;i++ ) pos[i].clear();
for( int i =0 ;i < len;i++ ){
pos[str2[i]-'a'].push_back( i+1+m );
}
for(int i = 1;i <= m;i++ ){
int c = str1[i-1]-'a';
for( int j = 0;j < pos[ c ].size();j++ ){
// add( i,pos[c][j] );add( pos[c][j],i );
ve[i].push_back( pos[c][j] );
}
}
}
int cnt[maxm];
for( int i = 1;i <= m;i++ ){
memset( cnt,0,sizeof(cnt) );
for( int j = 0;j < ve[i].size();j++ ){
cnt[ ve[i][j] ]++;
}
for( int j = 2*m;j >= m+1;j-- ){
if( cnt[ j ]==n ){
add( i,j );add( j ,i);
}
}
}
int ans = 0;
for( int i = m;i >= 1;i-- ){
memset( vis,0,sizeof(vis) );
if( dfs(i) ) ans++;
}
if( ans != m || !flag ){
printf("-1\n");
}else {
int res[maxm];
for (int i = m + 1; i <= 2 * m; i++) {
res[match[i]] = i - m;
}
printf("%d",res[1]);
for (int i = 2; i <= m; i++) {
printf(" %d", res[i]);
}
printf("\n");
}
}
return 0;
}