旧题复习{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()); } }
Copyright:http://www.cnblogs.com/candy99/