旧题复习{6}

1.树形背包

洛谷P1273有线电视网==poj1155tele

//一个孩子一个分组,枚举每个组选几个(给每个孩子分配体积)
//沙茶的输出打错了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=3e3+5,INF=1e9;
int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int n,m,s,v,w;
struct edge{
    int v,w,ne;
}e[N<<1];
int h[N],cnt=0;
void ins(int u,int v,int w){
    cnt++;
    e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
}

int d[N][N],son[N];
void dfs(int u,int fa){
    if(u>=n-m+1) return;
    for(int j=1;j<=m;j++) d[u][j]=-INF;
    
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v,w=e[i].w;
        if(v==fa) continue;
        dfs(v,u);
        son[u]+=son[v];
        for(int j=son[u];j>=1;j--){
            int t=min(j,son[v]);
            for(int k=1;k<=t;k++)
                d[u][j]=max(d[u][j],d[u][j-k]+d[v][k]-w);
        }
    }
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n-m;i++){
        s=read();
        while(s--){v=read();w=read();ins(i,v,w);}
    }
    for(int i=n-m+1;i<=n;i++) d[i][1]=read(),son[i]=1;
    dfs(1,0);
    for(int i=m;i>=1;i--) if(d[1][i]>=0) {printf("%d",i);break;}
}

 


2.P2627 修剪草坪

状态损失最小而不是得到最大,就可以单调队列优化

最后n-k到n都可以作为答案

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e5+5;
typedef long long ll;
const ll INF=1e18;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,k,e;
int q[N],head=1,tail=0;
ll f[N],sum;
int main(){
    n=read();k=read();
    q[tail++]=0;
    for(int i=1;i<=n;i++){
        e=read(); sum+=e;
        while(head<=tail&&i-q[head]-1>k) head++;
        f[i]=f[q[head]]+e;
        while(head<=tail&&f[q[tail]]>=f[i]) tail--;
        q[++tail]=i;
    //    printf("f %d %d\n",i,f[i]);
    }
    ll mn=INF;
    for(int i=n-k;i<=n;i++) mn=min(mn,f[i]);
    printf("%lld",sum-mn);
}

 


 

3.poj1742coins

多重背包可行性 F[I][J]前i个凑成j还剩几个i

注意0是可行的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105,M=1e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,w[N],c[N];
int f[M];
void dp(){
    memset(f,-1,sizeof(f));
    f[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++){
            if(f[j]>=0) f[j]=c[i];    
            else f[j]=-1;
        }
        for(int j=0;j<=m-w[i];j++) 
            if(f[j]>0) f[j+w[i]]=max(f[j+w[i]],f[j]-1);
    }
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF&&n+m){
    for(int i=1;i<=n;i++) w[i]=read();
    for(int i=1;i<=n;i++) c[i]=read();
    dp();
    int ans=0;
    for(int j=1;j<=m;j++) if(f[j]>=0) ans++;//,printf("f %d\n",j);
    printf("%d\n",ans);
    }
}

 


 

4.洛谷P2423双塔==vijos

注意除了-1高度为0也是不可行

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105,M=2005;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,h[N],sum=0;
int f[2][M];
void dp(){
    int now=1;
    memset(f,-1,sizeof(f));
    f[0][0]=0;
    for(int i=1;i<=n;i++,now^=1){
        int pre=now^1;
        for(int j=0;j<=sum;j++){
            f[now][j]=f[pre][j];
            if(j-h[i]>=0&&f[pre][j-h[i]]!=-1) f[now][j]=max(f[now][j],f[pre][j-h[i]]+h[i]);
            if(f[pre][j+h[i]]!=-1) f[now][j]=max(f[now][j],f[pre][j+h[i]]);
            if(h[i]-j>0&&f[pre][h[i]-j]!=-1) f[now][j]=max(f[now][j],f[pre][h[i]-j]+j); 
        }
    }
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) h[i]=read(),sum+=h[i];
    dp();
    if(f[n&1][0]<=0) puts("Impossible");
    else printf("%d",f[n&1][0]);
}

 


5.LCIS

注意滚动数组的应用

mx就应该边推内层边取mx,因为mx取得位置要<j

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=505;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,a[N],b[N];
int f[N];
void dp(){
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++){
        int mx=0;
        for(int j=1;j<=m;j++){
            if(a[i]>b[j]) mx=max(mx,f[j]);
            if(a[i]==b[j]) f[j]=mx+1;
        }
    }
}
int main(){
    int T=read();
    while(T--){
        n=read(); for(int i=1;i<=n;i++) a[i]=read();
        m=read(); for(int i=1;i<=m;i++) b[i]=read();
        dp();
        int ans=0;
        for(int i=1;i<=m;i++) ans=max(ans,f[i]);
        printf("%d\n",ans);
    }
}

 


 

6.poj3636

二维偏序问题,注意排序时相等怎么办

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e4+5,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n;
struct doll{
    int w,h;
    bool operator <(const doll &r)const{
        if(w==r.w) return h>r.h;
        return w<r.w;
    }
}d[N];
int f[N],g[N],a[N];
inline bool cmp(int a,int b){return a>b;}
int dp(){
    int ans=0;
    for(int i=1;i<=n;i++) g[i]=-INF,a[i]=d[i].h;
    for(int i=1;i<=n;i++){
        int k=upper_bound(g+1,g+1+n,a[i],cmp)-g;
        f[i]=k;
        g[k]=a[i];
        ans=max(ans,f[i]);
        //printf("f %d %d\n",i,f[i]);
    }
    return ans;
}
int main(){
    int T=read();
    while(T--){
        n=read();
        for(int i=1;i<=n;i++) d[i].w=read(),d[i].h=read();
        sort(d+1,d+1+n);
        printf("%d\n",dp());
    }
}

 

posted @ 2016-11-17 08:16  Candy?  阅读(188)  评论(0编辑  收藏  举报