HDU 1054 Strategic Game
题目大意:一城堡的所有的道路形成一个n个节点的树,如果在一个节点上放上一个士兵,那么和这个节点相连的边就会被看守住,问把所有边看守住最少需要放多少士兵。 dproot[ i ] 表示以i为根的子树,在i上放置一个士兵,看守住整个子树需要多少士兵。
掌握了一个图论知识:图的最小点覆盖=二分图的最大匹配
#include <cstdio> #include <cstring> #include <vector> using namespace std; const int N=100000; int link[N],used[N]; vector v[N]; int Dfs(int k){ for(int i=0;i<v[k].size();i++){ int a=v[k][i]; if(used[a]==0){ used[a]=1; if(link[a]==-1||Dfs(link[a])){link[a]=k;return 1;} } }return 0; } int main(){ int i,count,a,n,b,t,k; while(~scanf("%d",&n)){ k=n; memset(link,-1,sizeof(link)); for(i=0;i<n;i++)v[i].clear(); while(n--){ scanf("%d:(%d)",&a,&b); while(b--){ scanf("%d",&t); v[a].push_back(t); v[t].push_back(a); } }count=0; for(i=0;i<k;i++){ memset(used,0,sizeof(used)); if(Dfs(i))count++; } printf("%d\n",count/2); } return 0; }
树形Dp的效率明显比二分图匹配简单,而且编程复杂度低……
#include <cstring> #include <cstdio> #include <vector> #include <algorithm> using namespace std; const int N=1505; int tree[N],all[N]; vector v[N]; void Dfs(int root,int father){ tree[root]=1; int sum=0; for(int i=0;i<v[root].size();i++){ int son=v[root][i]; if(son!=father){ Dfs(son,root); tree[root]+=all[son]; //覆盖当前点 sum+=tree[son]; //覆盖当前点的儿子节点 } } all[root]=min(sum,tree[root]); //DP取最优方案 } int main(){ int i,count,a,n,b,t,k; while(~scanf("%d",&n)){ k=n; for(i=0;i<n;i++)v[i].clear(); while(n--){ scanf("%d:(%d)",&a,&b); while(b--){ scanf("%d",&t); v[a].push_back(t); v[t].push_back(a); } } Dfs(0,0); printf("%d\n",min(tree[0],all[0])); } return 0; }
愿你出走半生,归来仍是少年