题意很简单,在一颗树上找最小点覆盖。
将树染成黑白两色,构成一张二分图,然后最大匹配==最小点覆盖即可,所以一次匈牙利就可以求出来了
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #include <string> #include <queue> #include <vector> #include <stdlib.h> using namespace std; #define N 1505 int n; struct node { int to,next; }edge[N*2]; vector<int>g[N]; int pre[N],cnt; int cao[N],a[N],b[N]; int cnta,cntb; int mark[N],frt[N]; void add_edge(int u,int v) { edge[cnt].to=v; edge[cnt].next=pre[u]; pre[u]=cnt++; } void Dfs(int s,int fr,int flag) { if(flag==0) { cao[s]=cnta; a[cnta]=s; cnta++; }else { cao[s]=cntb; b[cntb]=s; cntb++; } for(int p=pre[s];p!=-1;p=edge[p].next) { int v=edge[p].to; if(v==fr) continue; Dfs(v,s,flag^1); } } int dfs(int s) { for(int i=0;i<g[s].size();i++) { int v=g[s][i]; if(mark[v]==1) continue; mark[v]=1; if(frt[v]==-1||dfs(frt[v])) { frt[v]=s; return 1; } } return 0; } int main() { while(scanf("%d",&n)!=EOF) { cnt=0; memset(pre,-1,sizeof(pre)); for(int i=0;i<n;i++) { int x; scanf("%d",&x); int num; scanf(":(%d)",&num); for(int j=0;j<num;j++) { int y; scanf("%d",&y); add_edge(x,y); add_edge(y,x); } } //然后就是染色了 cnta=0; cntb=0; Dfs(0,-1,0); //然后再建一张图 for(int i=0;i<cnta;i++) { g[i].clear(); for(int p=pre[a[i]];p!=-1;p=edge[p].next) { int v=edge[p].to; g[i].push_back(cao[v]); } } int ans=0; memset(frt,-1,sizeof(frt)); for(int i=0;i<cnta;i++) { memset(mark,0,sizeof(mark)); ans+=dfs(i); } printf("%d\n",ans); } return 0; }
时间: 2024-10-07 03:55:29