HDU - 3861 The King’s Problem (强连通分量+最小路径覆盖)
思路:tarjarn缩点,然后剩下的就是纯粹的最小路径覆盖,最小路径覆盖=顶点数-匹配数。匹配数跑一遍匈牙利即可。
1 #include <iostream> 2 #include <queue> 3 #include <stack> 4 #include <cstdio> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <bitset> 9 #include <algorithm> 10 #include <cmath> 11 #include <cstring> 12 #include <cstdlib> 13 #include <string> 14 #include <sstream> 15 #include <time.h> 16 #define x first 17 #define y second 18 #define pb push_back 19 #define mp make_pair 20 #define lson l,m,rt*2 21 #define rson m+1,r,rt*2+1 22 #define mt(A,B) memset(A,B,sizeof(A)) 23 using namespace std; 24 typedef long long LL; 25 //const double PI = acos(-1); 26 const int N=5e5+10; 27 const LL mod=1e9+7; 28 const int inf = 0x3f3f3f3f; 29 const LL INF=0x3f3f3f3f3f3f3f3fLL; 30 const int MAXN = 5010;//点数 31 const int MAXM = 200010;//边数 32 struct Edge 33 { 34 int to,next; 35 } edge[MAXM],edge1[MAXM]; 36 int head[MAXN],tot; 37 int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc 38 int Index,top; 39 int scc;//强连通分量的个数 40 bool Instack[MAXN]; 41 int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc 42 //num数组不一定需要,结合实际情况 43 void addedge(int u,int v) 44 { 45 edge[tot].to = v; 46 edge[tot].next = head[u]; 47 head[u] = tot++; 48 } 49 void Tarjan(int u) 50 { 51 int v; 52 Low[u] = DFN[u] = ++Index; 53 Stack[top++] = u; 54 Instack[u] = true; 55 for(int i = head[u]; i != -1; i = edge[i].next) 56 { 57 v = edge[i].to; 58 if( !DFN[v] ) 59 { 60 Tarjan(v); 61 if( Low[u] > Low[v] )Low[u] = Low[v]; 62 } 63 else if(Instack[v] && Low[u] > DFN[v]) 64 Low[u] = DFN[v]; 65 } 66 if(Low[u] == DFN[u]) 67 { 68 scc++; 69 do 70 { 71 v = Stack[--top]; 72 Instack[v] = false; 73 Belong[v] = scc; 74 num[scc]++; 75 } 76 while( v != u); 77 } 78 } 79 void solve(int N) 80 { 81 memset(DFN,0,sizeof(DFN)); 82 memset(Instack,false,sizeof(Instack)); 83 memset(num,0,sizeof(num)); 84 Index = scc = top = 0; 85 for(int i = 1; i <= N; i++) 86 if(!DFN[i]) 87 Tarjan(i); 88 } 89 int head1[MAXN],tot1; 90 void init() 91 { 92 tot = 0; 93 tot1 = 0; 94 memset(head,-1,sizeof(head)); 95 memset(head1,-1,sizeof(head1)); 96 } 97 void addedge1(int u,int v) 98 { 99 edge1[tot1].to = v; 100 edge1[tot1].next = head1[u]; 101 head1[u] = tot1++; 102 } 103 int linker[MAXN]; 104 bool used[MAXN]; 105 bool dfs(int u) 106 { 107 for(int i = head1[u]; i != -1 ; i = edge1[i].next) 108 { 109 int v = edge1[i].to; 110 if(!used[v]) 111 { 112 used[v] = true; 113 if(linker[v] == -1 || dfs(linker[v])) 114 { 115 linker[v] = u; 116 return true; 117 } 118 } 119 } 120 return false; 121 } 122 int hungary(int uN) 123 { 124 int res = 0; 125 memset(linker,-1,sizeof(linker)); 126 for(int u = 1; u <=uN; u++) 127 { 128 mt(used,0); 129 if(dfs(u)) 130 { 131 res++; 132 } 133 } 134 return res; 135 } 136 int main() 137 { 138 #ifdef Local 139 freopen("data.txt","r",stdin); 140 #endif 141 ios::sync_with_stdio(false); 142 cin.tie(0); 143 int T; 144 int n,m,u,v; 145 cin>>T; 146 while(T--) 147 { 148 cin>>n>>m; 149 init(); 150 for(int i=0; i<m; i++) 151 { 152 cin>>u>>v; 153 addedge(u,v); 154 } 155 solve(n); 156 for(int i=1; i<=n; i++) 157 { 158 for(int j=head[i]; ~j; j=edge[j].next) //j表示读入的是第几条边 159 { 160 if(Belong[i]!=Belong[edge[j].to]) 161 { 162 addedge1(Belong[i],Belong[edge[j].to]); 163 //cout<<Belong[i]<<"->"<<Belong[edge[j].to]<<endl; 164 } 165 } 166 } 167 //cout<<hungary(scc)<<endl; 168 cout<<scc-hungary(scc)<<endl; 169 } 170 #ifdef Local 171 cerr << "time: " << (LL) clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl; 172 #endif 173 }