Week 8 DP

 P1616 疯狂的采药

 

#include<iostream>
using namespace std;
int main(){
	long long w1[100000005];int w2[10005];
	long long ans[10000005];
	long long t;int m;cin>>t>>m;
	for(int i=1;i<=m;i++)cin>>w1[i]>>w2[i];
	for(int i=1;i<=m;i++){
		for(long long j=w1[i];j<=t;j++){
			ans[j]=max(ans[j],ans[j-w1[i]]+w2[i]);
		}
	}
	cout<<ans[t];
	return 0;
}

 P1833 樱花

#include<iostream>
#include<cstdio>
using namespace std;

//存状态的答案,经过二进制拆分后的美学值,经过二进制拆分的耗时,经过二进制拆分后的物品数量
int ans[10000], c[100000], t[100000], rn = 0;
//存某个物品是否是完全背包(拆分后的物品)
bool infinity[100000];

//添加一个物品(用于拆分物品)
//参数:美学值,耗时,可观看次数(0是无限次,1是一次,拆分后不存在其他的次数)
void add(int ac, int at, int ap)
{
    rn++;
    c[rn] = ac;
    t[rn] = at;
    infinity[rn] = ap == 0;
}

int main()
{
    //n、现在时间的时、现在时间的分、上学时间的时、上学时间的分、现在到上学的时间
    int n, sh, sm, eh, em, tt;
    scanf("%d:%d %d:%d %d", &sh, &sm, &eh, &em, &n);
    //计算现在到上学的时间
    tt = em - sm + (eh - sh) * 60;
    //读
    for (int i = 1; i <= n; i++)
    {
        //耗时,美学值,次数
        int ti, ci, pi;
        cin >> ti >> ci >> pi;
        //如果时多重背包
        if (pi > 1)
        {
            //二进制拆分
            int temp = 1;
            //拆分成数量为 1, 2, 2 ^ 2, ..., 2 ^ (n - 1) 的部分
            while (temp * 2 - 1 <= pi)
            {
                add(temp * ci, temp * ti, 1);
                temp *= 2;
            }
            //超过 2 ^ n - 1 的部分
            int left = pi - temp + 1;
            if (left != 0)
            {
                add(left * ci, left * ti, 1);
            }
        }
        //01背包或者完全背包
        else
        {
            add(ci, ti, pi);
        }
    }

    for (int i = 1; i <= rn; i++)
    {
        //完全背包
        if (infinity[i])
        {
            //完全背包模板
            for (int j = t[i]; j <= tt; j++)
            {
                ans[j] = max(ans[j], ans[j - t[i]] + c[i]);
            }
        }
        //01背包
        else
        {
            //01背包模板
            for (int j = tt; j >= t[i]; j--)
            {
                ans[j] = max(ans[j], ans[j - t[i]] + c[i]);
            }
        }
    }
    cout << ans[tt] << endl;
    return 0;
}

P1077 [NOIP2012 普及组] 摆花 

dfs写法:

#include<bits/stdc++.h>
using namespace std;
const int maxn=105, mod = 1000007;
int n, m, a[maxn];
int dfs(int x,int y){//x种花y盆
	if(y>m)return 0;
	if(y==m)return 1;
	if(x>n)return 0;
	int ans=0;
	for(int i=0;i<=a[x];i++)
	   ans+=dfs(x+1,y+i);
	return ans;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    cout<<dfs(1,0);
    return 0;
}

动态规划: 

#include<bits/stdc++.h>
using namespace std;
const int maxn=105, mod = 1000007;
int n, m, a[maxn], f[maxn][maxn];
int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++) cin>>a[i];
    f[0][0] = 1;
    for(int i=1; i<=n; i++){
		for(int j=0; j<=m; j++){
			for(int k=0; k<=min(j, a[i]); k++){
				f[i][j] = (f[i][j] + f[i-1][j-k])%mod;
			}
		}
	}  
    cout<<f[n][m]<<endl;
    return 0;
}

P1064 [NOIP2006 提高组] 金明的预算方案 

 

#include<iostream>
using namespace std;
//最大的钱的数量、最大的物品数
constexpr int maxN = 3.2e4 + 5, maxM = 60 + 5;
//钱的数量、物品数、存每组物品的价值、存每组物品的重要度、存放每个状态的答案
int n, m, v[maxM][3], w[maxM][3], ans[maxN];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int tv, tp, tq;
        cin >> tv >> tp >> tq;
        //是主件
        if (tq == 0)
        {
            v[i][0] = tv;
            w[i][0] = tp;
        }
        //是附件
        else
        {
            //是第一个附件
            if (v[tq][1] == 0)
            {
                v[tq][1] = tv;
                w[tq][1] = tp;
            }
            //是第二个附件
            else
            {
                v[tq][2] = tv;
                w[tq][2] = tp;
            }
        }
    }

    //01背包
    for (int i = 1; i <= m; i++)
    {
        //只对存有物品组的做内层循环
        if (v[i][0] != 0)
        {
            for (int j = n; j >= v[i][0]; j--)
            {
                //不选或只选主件
                ans[j] = max(ans[j], ans[j - v[i][0]] + w[i][0] * v[i][0]);
                //能选主件+1号附件时
                if (j >= v[i][0] + v[i][1])
                {
                    ans[j] = max(ans[j], ans[j - v[i][0] - v[i][1]] + w[i][0] * v[i][0] + w[i][1] * v[i][1]);
                }
                //能选主件+2号附件时
                if (j >= v[i][0] + v[i][2])
                {
                    ans[j] = max(ans[j], ans[j - v[i][0] - v[i][2]] + w[i][0] * v[i][0] + w[i][2] * v[i][2]);
                }
                //能选主件+所有附件时
                if (j >= v[i][0] + v[i][1] + v[i][2])
                {
                    ans[j] = max(ans[j], ans[j - v[i][0] - v[i][2] - v[i][1]] + w[i][0] * v[i][0] + w[i][2] * v[i][2] + w[i][1] * v[i][1]);
                }
            }
        }
    }
    cout << ans[n] << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值