10-10——10-17ACM总结

做了下背包的题
题目:给出两个数n,m。m代表求出的n的划分中最大值不能超过m。比如n=5,m=3。则用1,2,3这三个数去分割5。求方案数。
f(n,m)代表求不超过m的n的划分数。
f(n,m)=1;n=1或m=1
f(n,m)=f(n,n);n<m
f(n,m)=f(n,m-1);n==m
f(n,m)=f(n-m,m)+f(n,m-1);n>m选m或不选m
这个题n的范围是1000,m的范围是100,最后求出的划分数明显大于10^18,所以这里需要修改一下状态转移方程。
状态转移方程:a[n]+=a[n-m]; a[n]%=INF;求10^18前面的数。
b[j]+=b[j-i]+(a[j]+a[j-i])/INF;求10^18后面的数。最后如果划分数大于INF,结果为两者之和,否则为a[n]。

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include<cstring>
#define ll 0x3f3f3f
using namespace std;

long long INF,a[1010],b[1010];

int main()
{
    int n,k;
    INF=1;
    for(int i=0; i<18; i++)
        INF*=10;
   cin>>n>>k;
        memset(b,0,sizeof(b));
        memset(a,0,sizeof(a));
        a[0]=1;

        for(int i=1; i<=k; i++)
        {
            for(int j=i; j<=n; j++)
            {
                b[j]+=b[j-i]+(a[j]+a[j-i])/INF;
                a[j]+=a[j-i];
                a[j]%=INF;
            }
        }
        if(b[n])
           cout<<b[n];
        cout<<a[n]<<endl;

    return 0;
}

道路
W 国的交通呈一棵树的形状。W 国一共有n - 1n−1个城市和nn个乡村,其中城市从11到n - 1n−1 编号,乡村从11到nn编号,且11号城市是首都。道路都是单向的,本题中我们只考虑从乡村通往首都的道路网络。对于每一个城市,恰有一条公路和一条铁路通向这座城市。对于城市i, 通向该城市的道路(公路或铁路)的起点,要么是一个乡村,要么是一个编号比ii大的城市。 没有道路通向任何乡村。除了首都以外,从任何城市或乡村出发只有一条道路;首都没有往 外的道路。从任何乡村出发,沿着唯一往外的道路走,总可以到达首都。

W 国的国王小 W 获得了一笔资金,他决定用这笔资金来改善交通。由于资金有限,小 W 只能翻修n - 1n−1条道路。小 W 决定对每个城市翻修恰好一条通向它的道路,即从公路和铁 路中选择一条并进行翻修。小 W 希望从乡村通向城市可以尽可能地便利,于是根据人口调 查的数据,小 W 对每个乡村制定了三个参数,编号为ii的乡村的三个参数是a_iai​,b_ibi​和c_ici​。假设 从编号为ii的乡村走到首都一共需要经过xx条未翻修的公路与yy条未翻修的铁路,那么该乡村 的不便利值为

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
	int n;
	struct node{LL x,y,z;} a[20010];
	int son[20010][5];
	LL f[20010][45][45];
LL dfs(int x,int p,int q)
{
	if(x>=n) return a[x-n+1].z*(a[x-n+1].x+p)*(a[x-n+1].y+q);
	if(f[x][p][q]!=f[n+1][41][41]) return f[x][p][q];
	return f[x][p][q]=min(dfs(son[x][0],p,q)+dfs(son[x][1],p,q+1),dfs(son[x][1],p,q)+dfs(son[x][0],p+1,q));
}
int main()
{
	int x,y;
	scanf("%d",&n);
	memset(f,63,sizeof(f));
	for(int i=1;i<n;i++)
	{
		scanf("%d %d",&x,&y);
		if(x<0) x=-x+n-1;
		if(y<0) y=-y+n-1;
		son[i][0]=x;
		son[i][1]=y;
	}
	for(int i=1;i<=n;i++)
		scanf("%lld %lld %lld",&a[i].x,&a[i].y,&a[i].z);
	printf("%lld",dfs(1,0,0));
}


解析看的题解:
直接考虑树形DP

设f [ u ] [ i ] [ j ] f[u][i][j]f[u][i][j]为从根节点到u节点经过了i条没经过标记的L边和j条没经过标记的R边

对于每个叶子节点直接枚举最佳答案
f [ u ] [ j ] [ j ] = c u ( a u + i ) ( b u + j ) f[u][j][j]=c_u(a_u+i)(b_u+j)
f[u][j][j]=c u (a u​ +i)(b u​ +j)
对于每个非叶子节点枚举左右删去哪条边
f [ u ] [ i ] [ j ] = m i n { f [ l s o n ] [ i + 1 ] [ j ] + f [ r s o n ] [ i ] [ j ] , f [ l s o n ] [ i ] [ j ] + f [ r s o n ] [ i ] [ j + 1 ] } f[u][i][j]=min{ f[lson][i+1][j]+f[rson][i][j],f[lson][i][j]+f[rson][i][j+1]}
f[u][i][j]=min{f[lson][i+1][j]+f[rson][i][j],f[lson][i][j]+f[rson][i][j+1]}

馒头:
有 M 种互不相同的馒头各一个,第 i 个馒头卖 Pi元。
有 N 个包装盒,第 j 个包装盒最多能装 Ci 个馒头,买第 j 个包装盒的花费为 Ej 元。要求只能将一些馒头放进包装盒中打包出售,不能零售,当然也可以不出售某些馒头(卖剩的馒头被出题人吃了,出题人还吃得津津有味~)。售出一盒馒头得到的利润为盒内所有馒头的价格减去包装盒的价格。
现在买下(这 N 个包装盒)其中的一些包装盒(也可以不买,还可以全买),将馒头打包出售,求最大可能利润。

#include<bits/stdc++.h>
using namespace std;
int n,m,a[10010],anss,dp[510][10010];
struct node{
	int c,e;
}b[510];
int cmp(int x,int y) {return x>y;}
int main()
{
	scanf("%d%d",&m,&n);
	for (int i=1;i<=m;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+m,cmp); 
	for (int i=1;i<=m;i++) a[i]+=a[i-1]; 
	for (int i=1;i<=n;i++) scanf("%d%d",&b[i].c,&b[i].e);
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=m;j++) 
	  {
	  	if (j<=b[i].c) dp[i][j]=max(dp[i-1][j],a[j]-b[i].e);	
	  	
	  	else dp[i][j]=max(dp[i-1][j],dp[i-1][j-b[i].c]+a[j]-a[j-b[i].c]-b[i].e);
	  
	    anss=max(anss,dp[i][j]); 
	  }
	cout<<anss<<endl;
	return 0;
}

比较简单的背包题,能独立做出来

总结:简单的能直接做出来,难的看下思路 能自己写出状态转移方程,比以前有很大进步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值