Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2916 Accepted Submission(s): 1217
Your program should find the minimum number of soldiers that Bob has to put for a given tree.
The input file contains several data sets in text format. Each data set represents a tree with the following description:
the number of nodes
the description of each node in the following format
node_identifier:(number_of_roads) node_identifier1 node_identifier2 ... node_identifier
or
node_identifier:(0)
The node identifiers are integer numbers between 0 and n-1, for n nodes (0 < n <= 1500). Every edge appears only once in the input data.
For example for the tree:
the solution is one soldier ( at the node 1).
The output should be printed on the standard output. For each given input data set, print one integer number in a single line that gives the result (the minimum number of soldiers). An example is given in the following table:
/* HDU 1054 Strategic Game 就是要找最小点覆盖。 一个二分图中的最大匹配数等于这个图中的最小点覆盖数 但这我们要扩展结点为n-n的匹配,无向图。 所以就是二分匹配数除于2就是答案了。 结点有1500个。用普通的匈牙利算法应该会超时的。 启用Hopcroft-Carp的算法。 G++ 6156ms 9428K */ #include<stdio.h> #include<algorithm> #include<string.h> #include<iostream> #include<queue> using namespace std; /* ********************************************* 二分图匹配(Hopcroft-Carp的算法)。 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ const int MAXN=1505; const int INF=1<<28; int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int v=0;v<Ny;v++) if(g[u][v]&&dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } return dis!=INF; } bool DFS(int u) { for(int v=0;v<Ny;v++) if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } //**************************************************************************/ int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int n; int u,k,v; while(scanf("%d",&n)!=EOF) { memset(g,0,sizeof(g)); for(int i=0;i<n;i++) { scanf("%d:(%d)",&u,&k); while(k--) { scanf("%d",&v); g[u][v]=1; g[v][u]=1; } } Nx=Ny=n; int ans=MaxMatch(); printf("%d\n",ans/2); } return 0; }
再附上一个用vector建立邻接表实现的匈牙利算法。效率比上面的高》
/* HDU 1054 用STL中的vector建立邻接表实现匈牙利算法 效率比较高 G++ 578ms 580K */ #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<vector> using namespace std; //************************************************ const int MAXN=1505; int linker[MAXN]; bool used[MAXN]; vector<int>map[MAXN]; int uN; bool dfs(int u) { for(int i=0;i<map[u].size();i++) { if(!used[map[u][i]]) { used[map[u][i]]=true; if(linker[map[u][i]]==-1||dfs(linker[map[u][i]])) { linker[map[u][i]]=u; return true; } } } return false; } int hungary() { int u; int res=0; memset(linker,-1,sizeof(linker)); for(u=0;u<uN;u++) { memset(used,false,sizeof(used)); if(dfs(u)) res++; } return res; } //***************************************************** int main() { int u,k,v; int n; while(scanf("%d",&n)!=EOF) { for(int i=0;i<MAXN;i++) map[i].clear(); for(int i=0;i<n;i++) { scanf("%d:(%d)",&u,&k); while(k--) { scanf("%d",&v); map[u].push_back(v); map[v].push_back(u); } } uN=n; printf("%d\n",hungary()/2); } return 0; }