Hoj 3134 Xiaodai’s Budget Program

来源:互联网 发布:按键精灵 链接数据库 编辑:程序博客网 时间:2024/04/30 02:35

题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=3134

根据依赖关系可以建立很多颗树,组成一个森林。然后我们增加一个虚拟节点0,使0作为这些子树根节点的父亲。那么这些森林

就组成了一颗以0为根的树。

接下来我们要在树上建立背包方程:

dp[s][i]代表以s为子树的情况花费了i元钱取得的最大重要度。

dp[s][i] = max(dp[s][i],dp[son][k] + dp[s][i-k]),son是s的儿子节点,k需要枚举。这其实是一个值可变的01背包问题,使用状态压缩时,第二维逆序。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <stack>#include <queue>#include <map>#include <algorithm>#include <iostream>using namespace std;#define Maxn 105#define Maxm 505struct Edge{    int a,b;}edge[Maxm];map<string,int> ma;bool notroot[Maxn];int first[Maxn];int next[Maxm];int total;int val[Maxn],deg[Maxn];int dp[Maxn][1005];int m,n,p;int num = 0;void addEdge(int a,int b){    edge[total].a = a,edge[total].b = b;    next[total] = first[a];    first[a] = total++;}void dfs(int s){    dp[s][val[s]] = deg[s];    for(int j=first[s];j!=-1;j=next[j])    {        int son = edge[j].b;        dfs(son);        //这里应该是01背包的第二维逆序        for(int i=p;i>=val[s];i--)        {            //不同于普通的01背包,需要枚举其值            for(int k=0;k<=i;k++)            {                if(dp[s][i-k]!=-1 && dp[son][k]!=-1)                    dp[s][i] = max(dp[s][i],dp[s][i-k] + dp[son][k]);            }        }    }}int main(){    #ifndef ONLINE_JUDGE        freopen("in.txt","r",stdin);    #endif    int temp1,temp2;    char name[260],name2[260];    while(scanf(" %d %d %d",&m,&n,&p)!=EOF)    {        ma.clear();        num = 0;        memset(notroot,false,sizeof(notroot));        total = 0;        memset(first,-1,sizeof(first));        memset(val,0,sizeof(val));        memset(deg,0,sizeof(deg));        memset(dp,-1,sizeof(dp));        for(int i=0;i<m;i++)        {            scanf(" %d %d %s",&temp1,&temp2,name);            if(ma.find(name) == ma.end())             {                ma[name] = ++num;                val[num] = temp1,deg[num] = temp2;            }        }        for(int i=0;i<n;i++)        {            scanf(" %s %s",name,name2);            addEdge(ma[name],ma[name2]);            notroot[ma[name2]] = true;        }        for(int i=1;i<=num;i++)        {            if(notroot[i] == false)            {                addEdge(0,i);            }        }        dfs(0);        int ans = 0;        for(int i=0;i<=p;i++)        {            ans = max(ans,dp[0][i]);        }        printf("%d\n",ans );    }    return 0;}