二分图:
二分图又称二部图,是图论中的一种特殊模型。设G=(V,E)是一个无向图,如果顶点V可以分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A, j in B), 则称图G是二分图。e.g.对于二分图的最大匹配,常用的求解方法是hungarian算法和最大流算法。
此题就是求最小路径覆盖
#include <stdio.h> #include <string.h> #include <vector> #include <stack> #include <algorithm> using namespace std; #define N 20005 stack<int>sta; vector<int>mp[N]; vector<int>mp2[N]; int match[N]; int dfn[N]; int low[N]; int InStack[N]; int indexx,number; int n, m; int id[N]; int vis[N]; void tarjan(int u) { InStack[u] = 1; low[u] = dfn[u] = ++ indexx; sta.push(u); for (int i = 0; i < mp[u].size(); ++ i) { int t = mp[u][i]; if (dfn[t] == 0) { tarjan(t); low[u] = min(low[u], low[t]); } else if (InStack[t] == 1) { low[u] = min(low[u], dfn[t]); } } if (low[u] == dfn[u]) { ++ number; while (!sta.empty()) { int v = sta.top(); sta.pop(); id[v]=number; InStack[v] = 0; if (v == u) break; } } } int path(int s)//求匹配度 { for(int i=0; i<mp2[s].size(); i++) { int v=mp2[s][i]; if(!vis[v]) { vis[v]=true; if(match[v]==-1 || path(match[v])) { match[v]=s; return 1; } } } return 0; } int main() { //freopen("input.txt","r",stdin); int T; while(scanf("%d",&T)==1) { while(T--) { scanf("%d%d",&n,&m); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(InStack, 0, sizeof(InStack)); indexx = number = 0; for (int i = 1; i <= n; ++ i) { mp[i].clear(); mp2[i].clear(); } while(!sta.empty()) sta.pop(); for(int i=1; i<=m; i++) { int a,b; scanf("%d%d",&a,&b); mp[a].push_back(b); } for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i); memset(dfn, 0, sizeof( dfn)); memset(low, 0, sizeof (low)); for(int i=1; i<=n; i++) { for(int j=0; j<mp[i].size(); j++) { if(id[i]!=id[mp[i][j]]) mp2[id[i]].push_back(id[mp[i][j]]); } } memset(match,-1,sizeof(match)); int ans=0; for(int i=1; i<=number; i++) { memset(vis,false,sizeof(vis)); ans+=path(i); } printf("%d\n",number-ans); } } }