hoj2819

匈牙利算法。在二分图中每行对应一个节点,每列对应一个节点,每个1对应一条连接该1所在行和列节点的边。如果最大匹配数==n则可行,否则不行。

对于可行的情况,只需要每次交换两个列节点的编号,直到所有的匹配都是行号==列号的为止。

View Code
   
     
#include < iostream >
#include
< cstdlib >
#include
< cstring >
#include
< cstdio >
#include
< vector >
using namespace std;

#define maxn 105

int n, ptn[maxn], ans[maxn][ 2 ], tot;
bool vis[maxn];
vector
< vector < int > > G(maxn);

void input()
{
for ( int i = 0 ; i < n; i ++ )
G[i].clear();
for ( int i = 0 ; i < n; i ++ )
for ( int j = 0 ; j < n; j ++ )
{
int a;
scanf(
" %d " , & a);
if (a == 1 )
G[i].push_back(j);
}
}

bool find( int a)
{
for ( int i = 0 ; i < G[a].size(); i ++ )
if ( ! vis[G[a][i]])
{
if (ptn[G[a][i]] == - 1 )
{
ptn[G[a][i]]
= a;
return true ;
}
vis[G[a][i]]
= true ;
if (find(ptn[G[a][i]]))
{
ptn[G[a][i]]
= a;
return true ;
}
}
return false ;
}

void work()
{
tot
= 0 ;
while ( 1 )
{
int a = - 1 ;
for ( int i = 0 ; i < n; i ++ )
if (ptn[i] != i)
{
a
= i;
break ;
}
if (a == - 1 )
return ;
while (ptn[a] != a)
{
ans[tot][
0 ] = a;
ans[tot][
1 ] = ptn[a];
tot
++ ;
int x = ptn[a];
swap(ptn[a], ptn[x]);
}
}
}

int main()
{
// freopen("D:\\t.txt", "r", stdin);
while (scanf( " %d " , & n) != EOF && n != - 1 )
{
input();
int ansi = 0 ;
memset(ptn,
- 1 , sizeof (ptn));
for ( int i = 0 ; i < n; i ++ )
{
memset(vis,
0 , sizeof (vis));
if (find(i))
ansi
++ ;
}
if (ansi < n)
{
printf(
" -1\n " );
continue ;
}
work();
printf(
" %d\n " , tot);
for ( int i = 0 ; i < tot; i ++ )
printf(
" C %d %d\n " , ans[i][ 0 ] + 1 , ans[i][ 1 ] + 1 );
}
return 0 ;
}

你可能感兴趣的:(OJ)