HDU 3861 The King’s Problem 强连通+二分匹配
题意:
1.互通的城市必须算一个州内
2.存在一条路径可以算一个州内
1. 想到强连通缩点
2.二分匹配
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #include<vector> const int INF = 1<<31-1; int min(int a,int b) { return a>b?b:a; } int max(int a, int b){ return a>b?a:b; } #define N 256004 //N为最大点数 #define M 256004 //M为最大边数 int n, m;//n m 为点数和边数 struct Edge{ int from, to, nex; bool sign;//是否为桥 }edge[M<<1]; int head[N], edgenum; void add(int u, int v){//边的起点和终点 Edge E={u, v, head[u], false}; edge[edgenum] = E; head[u] = edgenum++; } int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳) int taj;//连通分支标号,从1开始 int Belong[N];//Belong[i] 表示i点属于的连通分支 bool Instack[N]; vector<int> bcc[N]; //标号从1开始 void tarjan(int u ,int fa) { int i; DFN[u] = Low[u] = ++ Time ; Stack[top ++ ] = u ; Instack[u] = 1 ; for ( i = head[u] ; ~i ; i = edge[i].nex ) { int v = edge[i].to; if(DFN[v] == -1) { tarjan(v , u); Low[u] = min(Low[u] ,Low[v]) ; if(DFN[u] < Low[v]) { edge[i].sign = 1;//为割桥 } } else if(Instack[v]) { Low[u] = min(Low[u] ,DFN[v]) ; } } if(Low[u] == DFN[u]) { int now; taj ++ ; bcc[taj].clear(); do{ now = Stack[-- top] ; Instack[now] = 0 ; Belong [now] = taj ; bcc[taj].push_back(now); }while(now != u) ; } } void tarjan_init(int all){ memset(DFN, -1, sizeof(DFN)); memset(Low, -1, sizeof(Low)); memset(Instack, 0, sizeof(Instack)); memset(Stack, 0, sizeof(Stack)); top = Time = taj = 0; for(int i=1;i<=all;i++) if(DFN[i]==-1 ) tarjan(i, i); //注意开始点标!!! } vector<int>G[N]; int du[N]; void suodian() { int i; memset(du, 0, sizeof(du)); for( i = 1; i <= taj; i++) G[i].clear(); for(i = 0; i < edgenum; i++) { int u = Belong[edge[i].from], v = Belong[edge[i].to]; if(u!=v) { G[u].push_back(v), du[v]++; } } } int useif[N]; //记录y中节点是否使用 int link[N]; //记录当前与y节点相连的x的节点 int can(int t) { int i; for(i=0;i<G[t].size();i++) { int v=G[t][i]; if(useif[v]==0) { useif[v]=1; if(link[v]==-1 || can(link[v])) { link[v]=t; return 1; } } } return 0; } int MaxMatch() { int i,num; num=0; memset(link,-1,sizeof(link)); for(i=1;i<=taj;i++) { memset(useif,0,sizeof(useif)); if(can(i)) num++; } return num; } void init(){ memset(head, -1, sizeof(head)); edgenum=0; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); int i,j; init(); int a,b; for( i=0;i<m;i++) { scanf("%d%d",&a,&b); add(a,b); } tarjan_init(n); suodian(); if(taj==1) printf("1\n"); else { int ans=MaxMatch(); printf("%d\n",taj-ans); } } return 0; }