1、二分图
#define DeBUG
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <sstream>
#include <map>
#include <bitset>
using namespace std ;
#define zero {0}
#define INF 2000000000
#define EPS 1e-6
typedef long long LL;
const double PI = acos(-1.0);
inline int sgn(double x)
{
return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1);
}
const int N = 1505;
int pre[N];
bool flag[N];
std::vector<int > mp[N];
int n;
int find(int cur)
{
int i, k;
for (i = 0; i < mp[cur].size(); i++)
{
k = mp[cur][i];
if (!flag[k])
{
flag[k] = true;
if (pre[k] == -1 || find(pre[k]))
{
pre[k] = cur;
return 1;
}
}
}
return 0;
}
// bool 寻找从k出发的对应项出的可增广路
// {
// while (从邻接表中列举k能关联到顶点j)
// {
// if (j不在增广路上)
// {
// 把j加入增广路;
// if (j是未盖点 或者 从j的对应项出发有可增广路)
// {
// 修改j的对应项为k;
// 则从k的对应项出有可增广路, 返回true;
// }
// }
// }
// 则从k的对应项出没有可增广路, 返回false;
// }
// void 匈牙利hungary()
// {
// for i->1 to n
// {
// if (则从i的对应项出有可增广路)
// 匹配数++;
// }
// 输出 匹配数;
// }
int main()
{
#ifdef DeBUGs
freopen("//home//amb//桌面//1.in", "r", stdin);
#endif
int i, j, r, k, num, sum;
while (scanf("%d", &n) + 1)
{
memset(pre, -1, sizeof(pre));
for (i = 0; i < n; i++)
{
mp[i].clear();
}
for (i = 0; i < n; i++)
{
scanf("%d:(%d)", &k, &num);
for (j = 0; j < num; j++)
{
scanf("%d", &r);
mp[k].push_back(r);
mp[r].push_back(k);
}
}
sum = 0;
for (i = 0; i < n; i++)
{
memset(flag, false, sizeof(flag));
sum += find(i);
}
printf("%d\n", sum / 2);
}
return 0;
}
2、树形dp解法 来自http://fudq.blog.163.com/blog/static/1913502382012624105033673/
/*
树形DP:
yes表示该结点放士兵,子树所需的最少个数,no表示不放士兵最少个数
如果父节点放的话,那么父节点的最少个数即是子节sum{min(yes,no)};
如果父节点不放的话,那么父节点的最少个数是sum {子节点的yes}
* fudq.cpp
*
* Created on: 2012-07-24
* Author: fudq
*/
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<iomanip>
#include<string>
#include<string.h>
#include<math.h>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<iostream>
using namespace std;
#define N 1502
struct Node
{
int child[N];
int length;
int yes, no;
};
Node node[N];
int min(int a, int b)
{
return a < b ? a : b;
}
void dfs(int a)
{
int i;
node[a].yes = 1;
node[a].no = 0;
for (i = 0; i < node[a].length; i++)
{
dfs(node[a].child[i]);
node[a].yes += min(node[node[a].child[i]].yes, node[node[a].child[i]].no);
node[a].no += node[node[a].child[i]].yes;
}
}
int main()
{
//freopen("//home//amb//桌面//1.in","r",stdin);
int n, i, a, b, c, root;
while (scanf("%d", &n) != EOF)
{
for (i = 0; i < n; i++)
{
scanf("%d:(%d)", &a, &b);
if (i == 0)
root = a;
node[a].length = 0;
while (b--)
{
scanf("%d", &c);
node[a].child[node[a].length++] = c;
}
}
dfs(root);
printf("%d\n", min(node[root].yes, node[root].no));
}
return 0;
}
也是树形dp解法,来自http://blog.csdn.net/swm8023/article/details/6892587
#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
vector<int> m[1502];
int n, dr[1502], all[1502];
void dfs(int root, int father)
{
dr[root] = 1;
int sum = 0;
for (int i = 0; i < m[root].size(); i++)
{
int v = m[root][i];
if (v != father)
{
dfs(v, root);
dr[root] += all[v]; //在这一点放,只要下面的点被覆盖即可
sum += dr[v]; //在这一点不放,下一点必须放
}
}
all[root] = min(sum, dr[root]);
}
int main()
{
while (scanf("%d", &n) != EOF)
{
int u, ns, v;
for (int i = 0; i < n; i++)m[i].clear();
for (int i = 0; i < n; i++)
{
scanf("%d:(%d)", &u, &ns);
for (int i = 0; i < ns; i++)
{
scanf("%d", &v);
m[u].push_back(v);
m[v].push_back(u);
}
}
dfs(0, 0);
printf("%d\n", min(dr[0], all[0]));
}
return 0;
}