大意不在赘述。
思路:我自己想也想了1、2个小时,后来发现是求图的最大团问题,但是不知道怎么去求解,主要是连边不好连,还有不存在有效的算法,后来我突然发现可以建立原图的补图,于是大概思路也就出来了。
整理一下思路:
1、将男孩,女孩看做顶点,认知关系看做边,那么就是一个最大团问题,NP问题,至今无多项式解法。
2、本题一个附加条件:男生、女生之间相互认识,由于男生、女生相互认识,如果根据认知连边违反了二分图的定义。
3、于是根据2,我们转换一下思路,建立原图的补图,那么最大独立集元素个数等价于原图中最大完全子图(最大团)的顶点数。
4、在二分图中:有公式 最大独立集 = 顶点数-最大二分匹配。
至此, 答案也就出来了。
CODE:
#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cstdlib> #include <map> using namespace std; const int MAXN = 210; int nx, ny, m; int xlink[MAXN], ylink[MAXN]; int G[MAXN][MAXN]; bool vis[MAXN], flag[MAXN][MAXN]; void init() { memset(G, 0, sizeof(G)); memset(xlink, -1, sizeof(xlink)); memset(ylink, -1, sizeof(ylink)); memset(flag, 0, sizeof(flag)); } bool ED(int u) { for(int v = 1; v <= ny; v++) if(G[u][v]) { if(!vis[v]) { vis[v] = 1; if(ylink[v] == -1 || ED(ylink[v])) { xlink[u] = v; ylink[v] = u; return true; } } } return false; } void solve() { int ans = 0; for(int i = 1; i <= nx; i++) { if(xlink[i] == -1) { memset(vis, 0, sizeof(vis)); ans += ED(i); } } printf("%d\n", nx+ny-ans); } int main() { int times = 0; while(scanf("%d%d%d", &nx, &ny, &m) && (nx || ny || m)) { init(); while(m--) { int u, v; scanf("%d%d", &u, &v); G[u][v] = 1; flag[u][v] = 1; } for(int i = 1; i <= nx; i++) { for(int j = 1; j <= ny; j++) { if(G[i][j] && flag[i][j]) { G[i][j] = 0; } if(!G[i][j] && !flag[i][j]) { G[i][j] = 1; } } } printf("Case %d: ", ++times); solve(); } return 0; }