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;
}
posted @ 2011-03-19 15:19  金海峰  阅读(156)  评论(0编辑  收藏  举报