题目:http://acm.hdu.edu.cn/showproblem.php?pid=1054
以前用树形DP做过这个。最近学了二分图,找题就又看到了这个图。我们重新分析一下。因为他是放卫兵后他相邻的就可以不放。假设放置为1的集合,不放的为0的集合。我们就可以把他转换成二分图。所以理所当然就成里最小点覆盖。因为定理1,最小点覆盖==最大匹配边数。
#include<bits/stdc++.h>
#define INF 1e18
#define inf 1e9
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IOS ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int _max = 1505;
vector<int> mp[_max];
bool vis[_max];
int link[_max],n;
bool dfs(int rt){
for(int i = 0 ; i < mp[rt].size() ; i++){
int s = mp[rt][i];
if(!vis[s]) continue;
vis[s] = 0;
if(link[s] == -1 || dfs(link[s])){
link[s] = rt;
return true;
}
}
return false;
}
int hungary(){
int res = 0;
memset(link,-1,sizeof(link));
for(int u = 0 ; u < n ; u++){
memset(vis,1,sizeof(vis));
if(dfs(u)) res++;
}
return res;
}
int main(){
IOS;
int u,v,k;
while(cin>>n){
for(int i = 0 ; i < n ; i++) mp[i].clear();
for(int i = 1 ; i <= n ; i++){
cin>>u;
cin.get();cin.get();
cin>>k;
cin.get();cin.get();
for(int j = 1 ; j <= k ; j++){
cin>>v;
mp[u].push_back(v);
mp[v].push_back(u);
}
}
cout<<hungary()/2<<endl;
}
return 0;
}