LightOJ 1252 Maintaining Communities(树形)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1252

题意:给出一棵树,将其分成若干块,使得每块的权值之和均不大于m。求最少需要分成几块?

思路:f[u][id][c][flag]表示当前计算以u的第id个孩子为根的子树,flag表示u与u的父节点的关系:flag=1表示u是独立的一块,

flag=0表示u与u的父节点是一块,c表示u所在块内当前的权值。设u的第id个孩子为v,<u,v>=w。则转移为:

(1)若c+w<=m说明v可以与u在一个块上,则递归f[v][0][c+w][0]和f[u][id+1][len][flag](len为f[v][0][c+w][0]返回的权值);当然此时也可以选择v不与u在一个块上,则递归f[v][0][0][1]和f[u][id+1][c][flag];

(2)若c+w>m,则只能选择递归f[v][0][0][1]和f[u][id+1][c][flag]。

#include <iostream>

#include <cstdio>

#include <cstring>

#include <vector>

using namespace std;



struct node

{

    int v,w,next;



    node(){}

    node(int _v,int _w)

    {

        v=_v;

        w=_w;

    }

};



struct Node

{

    int cnt,len;



    Node(){}

    Node(int _cnt,int _len)

    {

        cnt=_cnt;

        len=_len;

    }

};



const int INF=1000000000;

const int MAX=105;

int C,num=0;

vector<node> G[MAX];

node edges[MAX*2];

int head[MAX],e;

int n,m;

Node f[MAX][MAX][MAX][2];

int visit[MAX][MAX][MAX][2];





void Add(int u,int v,int w)

{

    edges[e].v=v;

    edges[e].w=w;

    edges[e].next=head[u];

    head[u]=e++;

}



void DFS1(int u,int pre)

{

    int i,v,w;

    for(i=head[u];i!=-1;i=edges[i].next)

    {

        v=edges[i].v;

        w=edges[i].w;

        if(v==pre) continue;

        DFS1(v,u);

        G[u].push_back(node(v,w));

    }

}



Node DFS(int u,int id,int c,int flag)

{

    if(id==G[u].size()) return Node(flag,c);

    if(visit[u][id][c][flag]) return f[u][id][c][flag];

    visit[u][id][c][flag]=1;

    Node t1,t2,ans=Node(INF,INF);

    int v,w;

    v=G[u][id].v;

    w=G[u][id].w;

    if(c+w<=m)

    {

        t1=DFS(v,0,c+w,0);

        t2=DFS(u,id+1,t1.len,flag);

        ans=Node(t1.cnt+t2.cnt,t2.len);

    }

    t1=DFS(v,0,0,1);

    t2=DFS(u,id+1,c,flag);

    t2.cnt+=t1.cnt;



    if(t2.cnt<ans.cnt||t2.cnt==ans.cnt&&t2.len<ans.len) ans=t2;

    return f[u][id][c][flag]=ans;

}



int main()

{

    for(scanf("%d",&C);C--;)

    {

        scanf("%d%d",&n,&m);

        int i,u,v,w;

        for(i=1;i<=n;i++) G[i].clear(),head[i]=-1;

        e=0;

        for(i=1;i<n;i++)

        {

            scanf("%d%d%d",&u,&v,&w);

            Add(u,v,w);

            Add(v,u,w);

        }

        DFS1(1,-1);

        memset(visit,0,sizeof(visit));

        Node ans=DFS(1,0,0,1);

        printf("Case %d: %d\n",++num,ans.cnt);

    }

}

  

 

 

 

你可能感兴趣的:(main)