P1156 垃圾陷阱
f[i][j]表示前i个垃圾填j的高度的最大维持时间,一开始觉得这个方程式可以都用来吃从而得到最大时间,但是忘记了j在循环。
#include <bits/stdc++.h>
#include <algorithm>
using namespace std;
#define maxn 1001
#define INF 0x7f7f7f7f
#define max(x,y) x>y?x:y
int f[101][1001],sum;
struct arr{
int x,t,h;
}a[maxn];
int cmp(arr a,arr b){
return a.x<b.x;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&a[i].x,&a[i].t,&a[i].h);
sum+=a[i].t;
}
sort(a+1,a+m+1,cmp);
memset(f,0xA0,sizeof f);
f[0][0]=10; a[0].x=a[0].t=a[0].h=0;
int fl=0;
//正的去推正的,这样得出的结果
// 负的可能推出正的,从而达到顶端
for (int i=1;i<=m;i++)
{
for (int j=0;j<=n;j++)
{
if (f[i-1][j]-a[i].x+a[i-1].x>=0)
f[i][j]=max(f[i][j],f[i-1][j]-a[i].x+a[i-1].x+a[i].t);
if (f[i-1][j-a[i].h]-a[i].x+a[i-1].x>=0 && j-a[i].h>=0)
//error if(j-a[i].h>=0)
f[i][j]=max(f[i][j],f[i-1][j-a[i].h]-a[i].x+a[i-1].x);
if (f[i][j]>=0 && j==n){
printf("%d\n",a[i].x);
fl=1;
return 0;
}
}
}
int ans=0;
if (!fl){
for(int i=1;i<=m;i++)
if(f[i][0]>0){
ans=max(ans,f[i][0]+a[i].x);//在第a[i].x 秒时获得的最大能量,加上之前的a[i].x就是存活时间
}
//还能存活的时间+已经存活的时间 a[i].x
printf("%d\n",ans);
}
//为什么不是把东西全吃了,活的最多?
//因为到下一次吃东西,还要消耗时间/体力
}
背包-中
飞扬的小鸟
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=10000+10;
const int maxm=2000+10;
int n,m,p;
int x[maxn],y[maxn]; //i位置,上升x[i],下降y[i]
int low[maxn],high[maxn]; //i位置能通过的范围是low[i]-high[i]
int f[maxn][maxm]; //到(i,j)的最少点击次数
int e[maxn]; //e[i]表示i位置有没有管道
int main() {
scanf("%d%d%d",&n,&m,&p);
for(int i=1; i<=n; ++i) scanf("%d%d",&x[i],&y[i]);
for(int i=1; i<=n; ++i) {
low[i]=0;
high[i]=m+1;
}
int a,b,c,t = 0;
for(int i=1; i<=p; ++i) {
scanf("%d%d%d",&a,&b,&c);
e[a]=1;
low[a]=b;
high[a]=c;
}
memset(f,0x3f,sizeof(f));
for(int i=1; i<=m; ++i) f[0][i]=0;
for(int i=1; i<=n; ++i) {
for(int j=x[i]+1; j<=m+x[i]; ++j)//前一步是可以达到m-x[i]中间的高度的
f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);
for(int j=m+1; j<=m+x[i]; ++j)
f[i][m]=min(f[i][m],f[i][j]);//天花板
for(int j=1; j<=m-y[i]; ++j)
f[i][j]=min(f[i][j],f[i-1][j+y[i]]);//下降
for(int j=1; j<=low[i]; ++j)
f[i][j]=f[0][0];
for(int j=high[i]; j<=m; ++j)
f[i][j]=f[0][0];
}
int ans=f[0][0];
for(int j=1;j<=m;++j) {
ans=min(ans,f[n][j]);
}
int fl = 0;
if(ans<f[0][0]) printf("1\n%d\n",ans);
else{
int i,j; ans = 0;
for(i=n;i>=1;i--) {//倒着,当这个是管道,且可以通过的时候,打标记
if(!e[i]) continue;
for(j=1;j<=m;++j) {
if(f[i][j]<f[0][0]){
fl = i;
break;
}
}
if(fl) break;
}
for(int i = 1; i <= fl; i++){//因为输入不是按照从小到大的顺序,因此只能数管道个数
if(e[i]) ans++;
}
printf("0\n%d\n",ans);
}
return 0;
}
P1364 医院设置 换根dp入门
//自下而上求每个子树到它的距离
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n, g[105], f[105], cnt, hd[105], sum[105], a[105], mx, ans;
struct Edge{
int to, nxt;
}edge[205];
void add(int u, int v){
cnt++;
edge[cnt].to = v;
edge[cnt].nxt = hd[u];
hd[u] = cnt;
}
void dfs(int u, int fa){
sum[u] = a[u];
for(int i = hd[u]; i; i = edge[i].nxt){
int v = edge[i].to;
if(v == fa) continue;
dfs(v, u);
sum[u] += sum[v];
f[u] += f[v] + sum[v];
}
}
void dfs1(int u, int fa){//换根
for(int i = hd[u]; i; i = edge[i].nxt){
int v = edge[i].to;
if(v == fa) continue;
g[v] = g[u] - sum[v] + (mx - sum[v]) ;
ans = min(ans, g[v]);
dfs1(v, u);
}
}
int main(){
scanf("%d",&n); int x,y;
for(int i = 1; i <= n; i++){
scanf("%d%d%d",&a[i],&x,&y);
add(i, x); add(i, y);
mx += a[i];
}
dfs(1, 0);
g[1] = f[1];
ans = f[1];
dfs1(1, 0);
// for(int i = 1; i <= n; i++)
// cout<<"hhh: "<<i<<" "<<g[i]<<endl;
printf("%d\n",ans);
return 0;
}