ural1781 Clean Code
我们记一次操作为一个二元组(i,j)
考虑矩阵中的元素a,它原来的位置是(x,y),则经过操作(i,j)后等价于分别对x和y做一次置换映射,这个置换映射就是s0=(i j),是一个轮换
因此每一个操作都可以看做一个轮换,所以操作并起来就是这些轮换的乘积,记为s,它还是一个置换映射
如果a原来的位置是(x,y),经过这一系列操作,最终的位置是(s(x),s(y))
对于每一个非零元素a(x,y),我们只要要求s(x)<=s(y)即可,当x=y时,显然有s(x)=s(y),而当x!=y时,有s(x)!=s(y)
因此只需使在x!=y时,s(x)<s(y)即可
我们可以建立一个拓扑排序模型,将1,2,...,n做拓扑排序,记它们在拓扑序列中的位置为s(1),s(2),...,s(n).
对于每一个非零元素a(x,y),且x!=y,必须满足s(x)<s(y),即从y到x添一条有向边
如果不能拓扑排序,则无解。否则得到s,把它拆成轮换的乘积,然后再把轮换拆成对换的乘积即可
#include
<
iostream
>
#include < cstdlib >
#include < cstdio >
using namespace std;
bool d[ 120 ][ 120 ];
int n,m, in [ 120 ],s[ 120 ],x[ 120 ],y[ 120 ];
bool b[ 120 ];
int main( void )
{
int i,j,k,t;
scanf( " %d " , & n);
for (i = 1 ;i <= n;i ++ )
{
in [i] = 0 ;
b[i] = true ;
}
for (i = 1 ;i <= n;i ++ )
for (j = 1 ;j <= n;j ++ )
{
d[i][j] = false ;
scanf( " %d " , & t);
if (i != j && t != 0 )
{
d[i][j] = true ;
in [j] ++ ;
}
}
for (i = 1 ;i <= n;i ++ )
{
k = 0 ;
for (j = 1 ;j <= n;j ++ )
if ( in [j] == 0 )
{
k = j;
break ;
}
if (k == 0 ) break ;
s[k] = i;
in [k] -- ;
for (j = 1 ;j <= n;j ++ )
if (d[k][j])
in [j] -- ;
}
if (i <= n)
{
printf( " %d\n " , - 1 );
return 0 ;
}
m = 0 ;
for (i = 1 ;i <= n;i ++ )
{
if ( ! b[i]) continue ;
b[i] = false ;
if (s[i] == i) continue ;
for (j = s[i];j != i;j = s[j])
{
b[j] = false ;
m ++ ;
x[m] = i;
y[m] = j;
}
}
printf( " %d\n " ,m);
for (i = 1 ;i <= m;i ++ )
printf( " %d %d\n " ,x[i],y[i]);
return 0 ;
}
#include < cstdlib >
#include < cstdio >
using namespace std;
bool d[ 120 ][ 120 ];
int n,m, in [ 120 ],s[ 120 ],x[ 120 ],y[ 120 ];
bool b[ 120 ];
int main( void )
{
int i,j,k,t;
scanf( " %d " , & n);
for (i = 1 ;i <= n;i ++ )
{
in [i] = 0 ;
b[i] = true ;
}
for (i = 1 ;i <= n;i ++ )
for (j = 1 ;j <= n;j ++ )
{
d[i][j] = false ;
scanf( " %d " , & t);
if (i != j && t != 0 )
{
d[i][j] = true ;
in [j] ++ ;
}
}
for (i = 1 ;i <= n;i ++ )
{
k = 0 ;
for (j = 1 ;j <= n;j ++ )
if ( in [j] == 0 )
{
k = j;
break ;
}
if (k == 0 ) break ;
s[k] = i;
in [k] -- ;
for (j = 1 ;j <= n;j ++ )
if (d[k][j])
in [j] -- ;
}
if (i <= n)
{
printf( " %d\n " , - 1 );
return 0 ;
}
m = 0 ;
for (i = 1 ;i <= n;i ++ )
{
if ( ! b[i]) continue ;
b[i] = false ;
if (s[i] == i) continue ;
for (j = s[i];j != i;j = s[j])
{
b[j] = false ;
m ++ ;
x[m] = i;
y[m] = j;
}
}
printf( " %d\n " ,m);
for (i = 1 ;i <= m;i ++ )
printf( " %d %d\n " ,x[i],y[i]);
return 0 ;
}