这题一开始理解有问题。
对于每一个洲,如果洲里面的任意两个城市u,v,如果u有路径到v,则v也要有路径到u。不要求两两城市都存在路径。
用Tarjan求强连通分量缩点,在用二分图求
#ifdef _MSC_VER #define DEBUG #endif #include <fstream> #include <stdio.h> #include <iostream> #include <string.h> #include <string> //#include <memory.h> #include <limits.h> #include <algorithm> #include <math.h> #include <numeric> #include <functional> #include <ctype.h> #include <vector> using namespace std; #define MAX 50005 //题目中可能的最大点数 int STACK[MAX],top; //Tarjan 算法中的栈 bool InStack[MAX]; //检查是否在栈中 int DFN[MAX]; //深度优先搜索访问次序 int Low[MAX]; //能追溯到的在栈中的最早次序 int ComponentNumber; //有向图强连通分量个数 int Index; //索引号 vector <int> Edge[MAX]; //邻接表表示 int InComponent[MAX]; //记录每个点在第几号强连通分量里 void Tarjan(int i) { int j; DFN[i]=Low[i]=Index++; InStack[i]=true; STACK[++top]=i; for (size_t e=0;e<Edge[i].size();e++) { j=Edge[i][e]; if (DFN[j]==-1) { Tarjan(j); Low[i]=min(Low[i],Low[j]); } else if (InStack[j]) //如果指向的节点j仍在栈中,由于j先于i入栈,则j有到i的通路,同时由于i指向j,则i与j构成回路 Low[i]=min(Low[i],DFN[j]); //如果指向的节点扔在栈中,则指向的节点仍未编入强连通分量 //如果前面两个判断条件都是错误的话,则i和j不在同一个连通分量中 } if (DFN[i]==Low[i]) //连通分量中最早进栈的点 { ComponentNumber++; do { j=STACK[top--]; InStack[j]=false; // Component[ComponentNumber].push_back(j); InComponent[j]=ComponentNumber; //给每一个连通分量上的节点染色 } while (j!=i); } } void solve(int N) //N是此图中点的个数,注意是0-indexed! { memset(STACK,-1,sizeof(STACK)); memset(InStack,0,sizeof(InStack)); memset(DFN,-1,sizeof(DFN)); memset(Low,-1,sizeof(Low)); top=0;Index=0;ComponentNumber=0; for(int i=1;i<=N;i++) if(DFN[i]==-1) Tarjan(i); } vector<int> v_component_edge[MAX]; int used[MAX]; int mat[MAX]; bool find(const int &x) { size_t i; for(i=0;i<v_component_edge[x].size();++i) { int v=v_component_edge[x][i]; if(!used[v]) { used[v]=1; if(mat[v]==-1 || find(mat[v])) { mat[v]=x; return true; } } } return false; } int main(void) { #ifdef DEBUG freopen("../stdin.txt","r",stdin); freopen("../stdout.txt","w",stdout); #endif int ncases,n,m,u,v; scanf("%d",&ncases); while(ncases--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) { Edge[i].clear(); v_component_edge[i].clear(); } while(m--) { scanf("%d%d",&u,&v); Edge[u].push_back(v); } solve(n); for(int i=1;i<=n;++i) for(size_t j=0;j<Edge[i].size();++j) if(InComponent[i]!=InComponent[Edge[i][j]]) v_component_edge[InComponent[i]].push_back(InComponent[Edge[i][j]]); int ans=0; memset(mat,-1,sizeof(mat)); for (int i=1;i<=ComponentNumber;++i) { memset(used,0,sizeof(used)); if(find(i)) ++ans; } printf("%d\n",ComponentNumber-ans); } return 0; }