hdu 1054 Strategic Game(树形DP||二分图)

小记:因为之前就已经做过这道题了,然后做题的周训上,又出了这道题,我脑子里有印象肯定做过,所以这道题没去想。没做。然后今天进hoj看了下,果然提交过,A了的。又因为昨天周训训的是dp,而我看了下我提交的代码是二分图做的,而题目显然是一道非常典型的树形dp,二分图我想不起来为什么二分图的解除以2是正解,因为是训练dp所以自己又动手码了树形dp,真经典,代码都很简单,1A啊。


思路:树形dp,或者二分图。二分图还不晓得为什么最大匹配就是正解这里就不讲了,贴贴代码。讲下树形dp

dproot[ i ]表示以i为根的子树,在i上放置一个士兵,看守住整个子树需要多少士兵。

all[ i ]表示看守住整个以i为根的子树需要多少士兵。

状态转移方程:dproot[i] = 1 + ∑dproot[j] (j是i的儿子)

all[i] = min(dproot[i],∑all[j]) (j是i的儿子)

对叶子节点,初始化为dproot[i] = 1, all[i] = 0;


最后的answer就是 min(dproot[root],all[root])  (root为根节点)


树形dp代码:

#include <stdio.h>
#include <string.h>
#include <stack>
#include <iostream>
#include <map>
#include <set>
#include <algorithm>
using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))

const int MAX_ = 1510;


struct node{
    int to,next,cap;
}edge[MAX_*MAX_];

int dproot[MAX_];
int all[MAX_];
bool vis[MAX_];
int head[MAX_];
int n, M;

void add(int from,int to){
    edge[M].to = to;
    edge[M].cap = 1;
    edge[M].next = head[from];
    head[from] = M++;
}

void dfs(int x,int pre){
    dproot[x] = 1;
    int sum = 0;
    for(int i = head[x]; i+1; i = edge[i].next){
        int v = edge[i].to;
        if(pre == v)continue;
        dfs(v,x);
        sum += dproot[v];
        dproot[x] += all[v];
    }
    all[x] = min(dproot[x],sum);
}



int main() {
    int T;
    int m, k;

    while(~scanf("%d",&n)){
        M = 0;
        mst(head,-1);

        for(int i = 0; i < n; ++i){
            scanf("%d:(%d)",&m,&k);
            while(k--){
                int t;
                scanf("%d",&t);
                add(m,t);
                add(t,m);
            }
        }
        dfs(0,-1);
        printf("%d\n",min(all[0],dproot[0]));
    }
    return 0;
}



二分图代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1501
typedef struct
{
    int to,next,cap;
}E;
E edge[N*N];
int V[N];
int dis[N];
int link[N];
int n,M;

void insert(int from,int to)
{
    edge[M].to=from;
    edge[M].cap=1;
    edge[M].next=V[to];
    V[to]=M++;
}
int dfs(int k)
{
    int i,t;
    for(i=V[k]; i+1; i=edge[i].next)
    {
        t=edge[i].to;
        if(!dis[t])
        {
            dis[t]=1;
            if(link[t]==-1||dfs(link[t]))
            {
                link[t]=k;
                return 1;
            }
        }
    }
   return 0;
}
int main()
{
    int i,j,m,num,k;
    while(~scanf("%d",&n))
    {
        memset(link,-1,sizeof(link));
        memset(V,-1,sizeof(V));
        M=0;
        for(i=0; i<n; i++)
        {
            scanf("%d:(%d)",&m,&k);
            while(k--)
            {
                scanf("%d",&j);
                insert(m,j);
                insert(j,m);
            }
        }
        num=0;
        for(i=0; i<n; i++)
        {
            memset(dis,0,sizeof(dis));
            if(dfs(i))num++;
        }
        printf("%d\n",num/2);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值