码迷,mamicode.com
首页 > 其他好文 > 详细

UVALive-7392 - Bundles of Joy【树型DP】【深搜】【好题】

时间:2016-08-07 23:27:08      阅读:552      评论:0      收藏:0      [点我收藏+]

标签:


UVALive-7392 - Bundles of Joy


技术分享
技术分享

题目链接:7392

题目大意:给出n种蛋糕,m家店。然后是m行,每行给出每家店买的蛋糕种类以及,买下这家店所有蛋糕的价格。问,怎么能用最少的钱买到n种蛋糕?
已知,A,B两家店蛋糕的种类满足

A完全包含B (B中有的蛋糕种类A中全有)
A完全不包含B (B中有的蛋糕种类,A全没有)

注意:可能存在AB两家店卖的蛋糕是一样的,这时候需要选择价格低的那家

题目思路:首先建树,如图所示,头结点为所以得蛋糕种类。

技术分享

然后从底部向上树形dp即可,

如果该节点的子节点组成的数组等于该节点,则更新该节点的dp值为两者最小值
否则,该节点的dp值为该节点的val值

以下是代码:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#include <deque>
#include <list>
using namespace std;
#define INF 1000000000
struct node
{
    int id,val;
    vector <int> s;
    vector <int> child;
}p[10005];
int dp[100005];
int vis[1005][1005];
map <vector<int> ,int> mp;
void init()
{
    mp.clear();
    memset(dp,0,sizeof(dp));
    memset(vis,0,sizeof(vis));   //记录第i个点第j个蛋糕是否可买
    for (int i = 0; i < 10004; i++)
    {
        p[i].id = 0;
        p[i].val = 0;
        p[i].child.clear();
        p[i].s.clear();
    }

}
bool cmp(node a,node b)
{
    if (a.s.size() != b.s.size())
        return a.s.size() < b.s.size();
    else return a.id > b.id;
}
bool cmp2(node a,node b)
{
    return a.id < b.id;
}
void solve(int r)
{
    int len = p[r].child.size();
    if (len == 0)   //如果没有儿子
    {
        dp[r] = p[r].val;
        return;
    }
    int sumchild = 0;
    vector <int> a;   //记录所有儿子的值
    for (int i = 0; i < len; i++)
    {
        int cld = p[r].child[i];
        solve(cld);  //搜儿子
        a.insert(a.end(),p[cld].s.begin(),p[cld].s.end());   //将所有儿子的值合并到一个数组中。
        sumchild += dp[cld];   //把儿子的权值加在一起
    }
    sort(a.begin(),a.end());
    sort(p[r].s.begin(),p[r].s.end());
    if (p[r].s == a)   //如果儿子能代替该父节点(eg:儿子:1,2,345; 父亲: 12345)
    {
        dp[r] = min(p[r].val,sumchild);
    }
    else
    {
        dp[r] = p[r].val;
    }
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n,m;
        cin >> m >> n;
        init();  //初始化
        p[0].id = 0;   //设置头结点
        for (int i = 1; i <= m; i++)
        {
            p[0].s.push_back(i);   //头结点的s数组值为全部的蛋糕编号
            vis[0][i] = 1;
        }
        p[0].val = INF;
        int tmp = 0;
        for (int i = 1,j = 1; j <= n; i++,j++)
        {
            cin >> p[i].val;
            int k;
            cin >> k;
            p[i].s.clear();
            memset(vis[i],0,sizeof(vis[i]));
            while(k--)
            {
                int num;
                cin >> num;
                p[i].s.push_back(num);
                vis[i][num] = 1;
            }
            p[i].id = i;
            //去重,如果该数组出现过,则与之前进行比较,记录下花费较小值。
            if (!mp[p[i].s]) mp[p[i].s] = i;
            else
            {
                p[mp[p[i].s]].val = min(p[i].val,p[mp[p[i].s]].val);
                i--;
                tmp++;   //记录删去了几个点
            }
        }
        n -= tmp;
        //找第i个结点的父节点
        sort(p,p + n + 1,cmp);
        for (int i = 0; i < n; i++)
        {
            for (int j = i + 1; j <= n; j++)
            {
                int ok = 1;
                for (int k = 0; k < p[i].s.size(); k++)  //遍历第i个店的所有蛋糕编号
                {
                    int no = p[i].s[k];
                    if (vis[p[j].id][no] == 0)   //如果第j个店不全部包括第i个店的所有蛋糕
                    {
                        ok = 0;
                        break;
                    }
                }
                if (ok)
                {
                    p[j].child.push_back(p[i].id);   //第j这个店的儿子是x这个店,注意存的是i的id值而不是i
                    break;
                }
            }
        }
        sort(p,p + n + 1,cmp2);
        solve(0);
        cout << dp[0] << endl;
    }
    return 0;
}
/*
 100
 4 3
 20 2 1 2
 20 2 3 4
 38 4 1 2 3 4

 2 3
 5 1 1
 10 2 1 2
 4 1 2

 2 2
 1 1 1
 5 2 2 1

 1 2
 2 1 1 
 1 1 1

 4 4
 10 2 1 2
 5 2 3 4
 10 2 3 4
 38 1 1

 10 5
 195 2 3 7
 1113 2 4 5
 99 1 8
 4510 2 2 3
 345 10 1 2 3 4 5 6 7 8 9 10

 10 5
 195 4 1 3 6 7
 234 6 2 4 5 8 9 10
 1000 10 1 2 3 4 5 6 7 8 9 10
 10 2 1 3
 10 2 6 7

 */

UVALive-7392 - Bundles of Joy【树型DP】【深搜】【好题】

标签:

原文地址:http://blog.csdn.net/loy_184548/article/details/52145087

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!