// 2712K 266MS G++
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define MAX 520
int G[MAX][MAX];
int G_F[MAX][MAX];
int iNum;
int sNum;
int V1[MAX];
int V2[MAX];
char waitingMove[MAX];
queue<int> BFSQueue;
char getPair(int checkId) {
for (int i = 1; i <= iNum; i++) {
if (G_F[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;
}
char BFSFlag[MAX]; // 0 no check / 1 found / 2 checked
void checkConnectibity(int checkId) {
memset(BFSFlag, 0, sizeof(BFSFlag));
while(BFSQueue.size()) {
BFSQueue.pop();
}
BFSQueue.push(checkId);
BFSFlag[checkId] = 1;
while(BFSQueue.size()) {
int curId = BFSQueue.front(); // get current checking node
BFSQueue.pop();
if (curId != checkId) {
G_F[checkId][curId] = 1;
}
for (int i = 1; i <= iNum; i++) { // check adjancey node
if (G[curId][i]) { // if connected
if (!BFSFlag[i]) { // if first found
BFSFlag[i] = 1;
BFSQueue.push(i);
}
}
}
BFSFlag[curId] = 2;
}
}
void solve() {
memcpy(G_F, G, sizeof(G));
for (int i = 1; i <= iNum; i++) {
checkConnectibity(i);
}
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++) {
while(1) {
memset(G, 0, sizeof(G));
memset(V1, 0, sizeof(V1));
memset(V2, 0, sizeof(V2));
scanf("%d %d", &iNum, &sNum);
if (iNum == 0 && sNum ==0) {
return 0;
}
for (int i = 0; i < sNum; i++) {
int iBegin;
int iEnd;
scanf("%d %d", &iBegin, &iEnd);
G[iBegin][iEnd] = 1;
}
solve();
}
}
和1422简直一模一样,除了一个关键的区别:1422的路径之间不能相交,直接符合最小路径覆盖,
而2594 则允许了路径覆盖,这样就不能直接用最小路径覆盖解了,e.g
5个点 1->2->3, 4->2->5, 如果按照最小路径覆盖,那么会最少需要3个robot遍遍历所有点(4 和 5被2隔开,但是2被1->2->3所覆盖,因此不能有4->2->5这个路径)
但是如果允许路径相交,那么只需要2个robot: 1->2->3 4->2->5即可。
这样,问题就变成了如何将这个允许相交转化,
注意到,4->5是相通的,如果按照最小路径覆盖,而且4到5是直达的话,那么最小路径覆盖的结果是正确的,
因此,要对点的连接关系做这样的预处理:以前只标示两个点是否直接可达,现在则标示两个点 是否 可达(中间可能会有多个点)。
这样,就绕过了相交点的影响,“飞”过了一样(4->2->5, 现在直接4->5).至于如何求可达,直接BFS/DFS每个点i即可,在图遍历中遇到的点j都是从i可达的
尝试进行了优化,及在遍历到某个点k时,如果点k的可达性测试之前完成了,那么对于k联通的点M,可以直接视为i也可达m(i->k->M 等价于 i->M),这样点k就不必在进入BFS
队列来增加运算,但是结果反而不理想,优化前200多ms,优化后438ms.....
上面的 飞过某个点 是个trick,要牢记。