http://poj.org/problem?id=1325
两台机器A,B,A有n个模式,B有m个模式,现在有k个工作,其中每一个工作可以由A或B中的一个特定模式来完成,但是切换机器的模式要重新启动一次,问最少要重启多少次机器才能完成所有工作?
A,B两台机器构成一个二分图,在之间按照给出的条件连边。这样想,每一个工作其实是由一条边来代表的,那么我们只要用最少的顶点来覆盖所有的边即可。这就是最小覆盖。
根据公式:最小覆盖=最大匹配;
对原二分图做一次最大匹配即可。
对了,针对这个题还有一个问题,就是起始状态下是在mode 0的,如果在这个模式下工作,是不需要切换mode的,所以只要有工作是在mode 0下(不管是在A还是在B),对这个工作就不连边,默认它不占匹配数!记得当时就是错在这里,转化很重要啊!
Source Code
Problem: 1325 | User: 541780774 | |
Memory: 412K | Time: 0MS | |
Language: G++ | Result: Accepted |
- Source Code
#include<stdio.h> #include<stdlib.h> #include<string.h> int nx, ny; // X的點數目、Y的點數目 int mx[101], my[101]; // X各點的配對對象、Y各點的配對對象 bool vy[101]; // 紀錄Graph Traversal拜訪過的點 bool adj[101][101]; // 精簡過的adjacency matrix // 以DFS建立一棵交錯樹 bool DFS(int x) { for (int y=0; y<ny; ++y) if (adj[x][y] && !vy[y]) { vy[y] = true; // 找到擴充路徑 if (my[y] == -1 || DFS(my[y])) { mx[x] = y; my[y] = x; return true; } } return false; } int bipartite_matching() { // 全部的點初始化為未匹配點。 memset(mx, -1, sizeof(mx)); memset(my, -1, sizeof(my)); // 依序把X中的每一個點作為擴充路徑的端點, // 並嘗試尋找擴充路徑。 int c = 0; for (int x=0; x<nx; ++x) // if (mx[x] == -1) // x為未匹配點,這行可精簡。 { // 開始Graph Traversal memset(vy, false, sizeof(vy)); if (DFS(x)) c++; } return c; } main() { int a,b,c,n,m,k; while(scanf("%d",&n),n!=0) { memset(adj, 0, sizeof(adj)); scanf("%d%d",&m,&k); while(k--) { scanf("%d%d%d",&a,&b,&c); if(b*c!=0) adj[b][c]=1; } nx=n; ny=m; printf("%d\n",bipartite_matching()); } system("pause"); }