//440K 0MS G++
#include <stdio.h>
#include <string.h>
#define MAX 125
int G[MAX][MAX];
int iNum;
int sNum;
int V1[MAX];
int V2[MAX];
char waitingMove[MAX];
char getPair(int checkId) {
for (int i = 1; i <= iNum; i++) {
if (G[checkId][i]) { // if checkId connect i
if (!V2[i]) { // if not assigned
V1[checkId] = i;
V2[i] = checkId;
return 1;
} else {
if (!waitingMove[V2[i]]) { // if i's owner is not waiting move
waitingMove[V2[i]] = 1; // try to move i's owner
if (getPair(V2[i])) { // move i's owner success
V1[checkId] = i;
V2[i] = checkId;
return 1;
}
}
}
}
}
return 0;
}
void solve() {
int maxMatchNum = 0;
for (int i = 1; i <= iNum; i++) {
memset(waitingMove, 0, sizeof(waitingMove));
if (getPair(i)) {
maxMatchNum++;
}
}
printf("%d\n", iNum - maxMatchNum);
}
int main() {
int caseNum;
scanf("%d", &caseNum);
for (int i = 0; i<caseNum; i++) {
memset(G, 0, sizeof(G));
memset(V1, 0, sizeof(V1));
memset(V2, 0, sizeof(V2));
scanf("%d %d", &iNum, &sNum);
for (int i = 0; i < sNum; i++) {
int iBegin;
int iEnd;
scanf("%d %d", &iBegin, &iEnd);
G[iBegin][iEnd] = 1;
}
solve();
}
}
Bite my shiny metal ass!
被最小边覆盖 和 最小路径覆盖搞晕了.
一个PXP的有向图中,路径覆盖就是在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每条路径就是一个弱连通子集.
from:http://blog.chinaunix.net/uid-22263887-id-1778941.html
路径覆盖的定义是:在有向图中找一些路径,使之覆盖了图中的所有顶点,就是任意一个顶点都跟那些路径中的某一条相关联,且任何一个顶点有且只有一条路径与之关联,一个单独的顶点是一条路径.最小路径覆盖就是最少的路径覆盖数。
如上图,最小路径覆盖的那条路应该是{e1,e4,e5,e6,e7},最小路径覆盖就是1。
最小路径覆盖 = 图的顶点数 – 最大匹配数。
其实那个最大匹配数并 非 原图 的最大匹配数,而是最小路径覆盖的边的条数,是把图中每个点拆成两个点,再算出来的最大匹配数。很容易证明两者是相同的。
可是有一点不明白,为什么原图用匈牙利算法算出最大匹配数,与图的顶点数想减,最后求出的最小路径覆盖是对的呢,而不需要用拆点后的图来算呢?
-----原来我建的邻接表它本身就拆点了,所以不矛盾。
唉,没有系统的看过二分图,原来还有最小路径覆盖,以前看到,还以为是最小边覆盖的另一种叫法,没留意,今天看了下图的术语,才发现路径和边是两码事,
题目要求的伞兵其实就是不相交的能覆盖每个点一次且仅一次的路径集(每个伞兵的行进路线就是这样一条路径),那么要求伞兵最小数量,自然就是最小覆盖路径集了。