T1:问题 A: 逃亡的准备
题目描述
在《Harry Potter and the Deathly Hallows》中,Harry Potter他们一起逃亡,现在有许多的东西要放到赫敏的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品,现在给出该种物品的数量、体积、价值的数值,希望你能够算出能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常地感谢你。
输入
第一行有 2 个整数,物品种数 n 和背包装载体积 v。
2 行到 i+1 行每行 3 个整数,为第 i 种物品的数量 m、体积 w、价值 s。
输出
包含一个整数,即为能拿到的最大的物品价值总和。
样例输入
2 10 3 4 3 2 2 5
样例输出
13
提示
【注释】
选第一种一个,第二种两个。结果为 3*1+5*2=13
【数据规模】
对于 30%的数据
1<=v<=500,1<=n<=2000,1<=m<=10,1<=w<=20,1<=s<=100
对于 100%的数据
1<=v<=500,1<=n<=2000,1<=m<=5000,1<=w<=20,1<=s<=100
题解
这道题是一道组合背包。可以考虑二进制压缩。而由于二进制可以拼成范围内的所有数,因此直接拆分成二进制的1,2,4,8……最后再来一个k。用01背包解决即可。
参考代码
#include<cstdio>
using namespace std;
int n,v,WEI[100001],VAL[100001];
int m,w,s,cnt=0,dp[100001],maxn=0;
int max1(int p,int q) { return p>q?p:q; }
int main()
{
scanf("%d%d",&n,&v);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&m,&w,&s);
int t=1;
while(m>t)
{
m-=t;
cnt++;
WEI[cnt]=t*w;
VAL[cnt]=t*s;
t*=2;
}
if(m)
{
cnt++;
WEI[cnt]=m*w;
VAL[cnt]=m*s;
}
}
for(int i=1;i<=cnt;i++)
{
for(int j=v;j>=WEI[i];j--)
{
dp[j]=max1(dp[j],dp[j-WEI[i]]+VAL[i]);
}
}
for(int i=1;i<=v;i++)
maxn=max1(maxn,dp[i]);
printf("%d",maxn);
return 0;
}
T2:问题 B: 种树
题目描述
现在我们国家开展新农村建设,农村的住房建设纳入了统一规划,统一建设,政府要求每一住户门口种些树。门口路边的地区被分割成块,并被编号成1..N。每个部分为一个单位尺寸大小并最多可种一棵树。每个居民房子门前被指定了三个号码B,E,T。这三个数表示该居民想在B和E之间最少种T棵树。当然,B≤E,居民必须记住在指定区不能种多于区域地块数的树,所以T≤E-B+l。居民们想种树的各自区域可以交叉。你的任务是求出能满足所有要求的最少的树的数量,尽量较少政府的支出。
输入
第一行包含数据N,M,区域的个数(0<N≤30000),房子的数目(0<m≤5000);
下面的m行描述居民们的需要:B E T,0<B≤E≤30000,T≤E-B+1。
输出
输出第一行写有树的数目,下面的行包括所有树的位置,相邻两数之间用一个空格隔开。
样例输入
9 4 3 5 2 1 4 2 4 6 2 8 9 2
样例输出
5
题解
这道题需要用到差分约束系统。首先定义dp[i]表示前i块最少种多少树。显然有:,只取决于第i+1块种不种树。这样就可以得到2类不等式。注意要把n+1带入,最后记录答案直接输出dp[n+1]即可。然后对于b到e种至少t棵树,可以表示为:。至于小于的不等式就没必要了,因为上两类不等式已经表达了相同的意思。由于求最小值,所以应该找最远路。用SPFA即可解决,注意DJ不能处理负权。(本题数据未要求输出位置,否则需要输出任意一条路径)。0也可以种树!
参考代码
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
struct tree
{
int nxt,to,dis;
}tr[90010];
queue<int>q;
int head[90010],cnt=0,d[90010];
int n,m,b,e,t,vis[90010];
void build_tree(int u,int v,int d)
{
tr[++cnt].nxt=head[u];
tr[cnt].to=v;
tr[cnt].dis=d;
head[u]=cnt;
}
int main()
{
memset(d,-127,sizeof(d));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&b,&e,&t);
build_tree(b-1,e,t);
}
for(int i=0;i<=n;i++)
{
build_tree(i+1,i,-1);
build_tree(i,i+1,0);
}
q.push(0);vis[0]=1;d[0]=0;
while(!q.empty())
{
int k=q.front();q.pop();
vis[k]=0;
for(int i=head[k];i;i=tr[i].nxt)
{
int to=tr[i].to;
if(d[to]<d[k]+tr[i].dis)
{
d[to]=d[k]+tr[i].dis;
if(!vis[to])
{
vis[to]=1;
q.push(to);
}
}
}
}
printf("%d",d[n+1]);
return 0;
}