这几天一直专心刷题。。。刷的是DP题,题目基本和下面博客上介绍的差不多
http://hi.baidu.com/lewutian/item/ffd19c2e640e17c1ef10f131
然后。。。贴代码
/* HOJ 1003 MaxSum 以前做过,和上一题也差不多,记录位置即可。DP */ #include <iostream> using namespace std; int main() { int cas,cas2,i,n,sum,max,a,b,num,begin; cin>>cas; cas2=cas; while(cas--) { sum=a=b=0; begin=1; max=-1001; cin>>n; for(i=0;i<n;i++) { cin>>num; sum+=num; if(sum>max) { max=sum; a=begin; b=i+1; } if(sum<0) { sum=0; begin=i+2; } } cout<<"Case "<<cas2-cas<<":\n"<<max<<' '<<a<<' '<<b<<endl; if(cas) cout<<endl; } }
/* HOJ 1024 Max Sum Plus Plus */ #include <iostream> using namespace std; const int N=1000101,INF=0x80000000; int d[N],g[N],a[N]; inline int min(int a,int b) { return a<b?a:b; } inline int max(int a,int b) { return a>b?a:b; } int main() { int i,j,m,n,t; while(~scanf("%d%d",&m,&n)) { for(i=1;i<=n;i++) { scanf("%d",a+i); d[i]=g[i]=INF; } for(i=1;i<=n;i++) { t=min(i,m); for(j=1;j<=t;j++) { d[j]=max(g[j-1],d[j])+a[i]; g[j-1]=max(g[j-1],d[j-1]); } g[j-1]=max(g[j-1],d[j-1]); } printf("%d\n",g[m]); } }
/* HOJ 1025 Constructing Roads In JGShining's Kingdom */ #include <iostream> #include <vector> #include <algorithm> using namespace std; int s[500001],dp[500001],g[500001]; int main() { int i,j,m,n,t,max,cas=1; while(~scanf("%d",&n)) { max=0; memset(g,0x7F,4*n+8); for(i=1;i<=n;i++) { scanf("%d%d",&t,&m); s[t]=m; } for(i=1;i<=n;i++) { j=lower_bound(g+1,g+n+1,s[i])-g; g[j]=s[i]; if(max<j) max=j; } printf("Case %d:\nMy king, at most %d road",cas++,max); if(max-1) printf("s"); printf(" can be built.\n\n"); } }
/* HOJ 1058 Humble Numbers 一开始一直在纠结这么大的数据范围,不会超时吗。。。。。。 建4个位置,存储即可。每个数字都要乘2,3,5,7的,比较下,相同的时候增大位置。 */ #include <iostream> using namespace std; int s[6000]; int t[4]; int min(int a,int b,int c,int d) { int m=a<b?a:b; int n=c<d?c:d; m=m<n?m:n; if(m==a) t[0]++; if(m==b) t[1]++; if(m==c) t[2]++; if(m==d) t[3]++; return m; } int main() { int i,n; s[0]=1; t[0]=t[1]=t[2]=t[3]=0; for(i=1;i<5842;i++) s[i]=min(2*s[t[0]],3*s[t[1]],5*s[t[2]],7*s[t[3]]); while(~scanf("%d",&i)&&i) { n=i-1; printf("The %d",i); i%=100; if(i!=11 && i%10==1) printf("st"); else if(i!=12 && i%10==2) printf("nd"); else if(i!=13 && i%10==3) printf("rd"); else printf("th"); printf(" humble number is %d.\n",s[n]); } }
/* HOJ 1059 分财产。。。简单多重背包问题,初始化为0即可,最终检测d[V]==V */ #include <iostream> using namespace std; const int MAXUP=60001; int UP,d[MAXUP]; inline int max(int a,int b) { return a>b?a:b; } void zpack(int cost,int weight) { for(int i=UP;i>=cost;i--) d[i]=max(d[i],d[i-cost]+weight); } void cpack(int cost,int weight) { for(int i=cost;i<=UP;i++) d[i]=max(d[i],d[i-cost]+weight); } void mpack(int cost,int weight,int amount) { if(weight*amount>+UP) { cpack(cost,weight); return; } int k=1; while(k<amount) { zpack(cost*k,weight*k); amount-=k; k+=k; } zpack(cost*amount,weight*amount); } int main() { int s[7],cas=1,flag,i; while(1) { UP=0; flag=1; for(i=1;i<=6;i++) { scanf("%d",s+i); UP+=s[i]*i; } if(!UP) break; if(UP&1) flag=0; else { UP/=2; memset(d+1,0,UP*4); for(i=1;i<=6;i++) mpack(i,i,s[i]); if(d[UP]!=UP) flag=0; } printf("Collection #%d:\nCan",cas++); if(!flag) printf("'t"); printf(" be divided.\n\n"); } }
/* HOJ 1078 FatMouse and Cheese DFS,保存中间子问题结果,就叫动态规划了 */ #include <iostream> using namespace std; int dp[102][102],map[102][102]; int k,n; int dir[4][2]={0,1,0,-1,1,0,-1,0}; int DFS(int x,int y) { int max=0,t; if(dp[x][y]) return dp[x][y]; for(int i=1;i<=k;i++) for(int j=0;j<4;j++) { int a=x+i*dir[j][0]; int b=y+i*dir[j][1]; if(a>0&&a<=n&&b>0&&b<=n&&map[x][y]<map[a][b]) { if(max<(t=DFS(a,b))) max=t; } } return dp[x][y]=max+map[x][y]; } int main() { int i,j; while(~scanf("%d%d",&n,&k)) { if(n==-1&&k==-1) continue; for(i=1;i<=n;i++) for(j=1;j<=n;j++) { scanf("%d",&map[i][j]); dp[i][j]=0; } DFS(1,1); printf("%d\n",dp[1][1]); } }
/* HOJ 1080 Human Gene Functions LCS升级版~用递归写的,感觉好写一点。。。 */ #include <iostream> using namespace std; char a[101],b[101]; int d[101][101]; int la,lb; int s[5][5]={ 5,-1,-2,-1,-3, -1,5,-3,-2,-4, -2,-3,5,-2,-2, -1,-2,-2,5,-1, -3,-4,-2,-1 }; int getCode(char ch) { if(ch=='A') return 0; if(ch=='C') return 1; if(ch=='G') return 2; if(ch=='T') return 3; return 0; } int DFS(int x,int y) { if(x<0&&y<0) return 0; if(x<0&&y>=0) return DFS(-1,y-1)+s[4][getCode(b[y])]; if(x>=0&&y<0) return DFS(x-1,-1)+s[getCode(a[x])][4]; if(d[x][y]) return d[x][y]; if(a[x]==b[y]) d[x][y]=DFS(x-1,y-1)+5; else d[x][y]=max(DFS(x-1,y-1)+s[getCode(a[x])][getCode(b[y])],max(DFS(x,y-1)+s[4][getCode(b[y])],DFS(x-1,y)+s[getCode(a[x])][4])); return d[x][y]; } int main() { int n; scanf("%d",&n); while(n--) { memset(d,0,sizeof(d)); scanf("%d",&la); scanf("%s",a); scanf("%d",&lb); scanf("%s",b); printf("%d\n",DFS(la-1,lb-1)); } }
/* HOJ 1081 To The Max Max sum ^ 3 */ #include <iostream> using namespace std; const int N=101; int map[N][N],s[N]; int main() { int i,j,k,n,ans,t; while(~scanf("%d",&n)) { ans=0x80000000; for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%d",&map[i][j]); for(i=1;i<=n;i++) { memset(s,0,4*n+4); for(j=i;j<=n;j++) { t=0; for(k=1;k<=n;k++) { s[k]+=map[j][k]; if(t<0) t=s[k]; else t+=s[k]; if(ans<t) ans=t; } } } printf("%d\n",ans); } }
/* HOJ 1114 Piggy-Bank 完全背包问题。初始化时全部赋值为最大值即可 */ #include <iostream> using namespace std; const int MAXD=5000001; int UP,dp[MAXD]; inline int min(int a,int b) { return a<b?a:b; } void zpack(int cost,int value) { for(int i=cost;i<=UP;i++) dp[i]=min(dp[i-cost]+value,dp[i]); } int main() { int cas,i,j,m,n,x,y; scanf("%d",&cas); while(cas--) { scanf("%d%d%d",&i,&UP,&n); UP-=i; memset(dp,0x7f,(UP+2)*sizeof(int)); dp[0]=0; for(i=0;i<n;i++) { scanf("%d%d",&x,&y); zpack(y,x); } if(dp[UP]>0x7F000000) printf("This is impossible.\n"); else printf("The minimum amount of money in the piggy-bank is %d.\n",dp[UP]); } }
/* HOJ 1158 Employment Planning 一道简单的DP,每月都会招人,所以都计算一下。。。。。。 每个月*招人的状态,转移是选最大 */ #include <iostream> using namespace std; int d[13][100],num[13]; int main() { int i,j,k,m,n,maxMan,minMoney,s,h,f,t; while(~scanf("%d",&n)&&n) { maxMan=0; scanf("%d%d%d",&h,&s,&f); for(i=1;i<=n;i++) { scanf("%d",num+i); if(maxMan<num[i]) maxMan=num[i]; } d[1][num[1]]=(s+h)*num[1]; for(i=num[1]+1;i<=maxMan;i++) d[1][i]=d[1][i-1]+s+h; for(i=2;i<=n;i++) for(j=num[i];j<=maxMan;j++) { minMoney=0x7FFFFFFF; for(k=num[i-1];k<=maxMan;k++) { if(j>k) t=h*(j-k)+j*s+d[i-1][k]; else t=f*(k-j)+j*s+d[i-1][k]; if(minMoney>t) minMoney=t; } d[i][j]=minMoney; } minMoney=0x7FFFFFFF; for(i=num[n];i<=maxMan;i++) if(minMoney>d[n][i]) minMoney=d[n][i]; printf("%d\n",minMoney); } }
/* HOJ 1159 Common Subsequence 最长相同子序列,以前做过,优化下,没用memset,发现速度快了很多。。。 */ #include <iostream> using namespace std; int dp[2013][2013]; char a[2013],b[2013]; int main() { int i,j,lena,lenb; while(~scanf("%s%s",a,b)) { lena=strlen(a); lenb=strlen(b); for(i=0;i<lena;i++) dp[0][i]=0; for(i=0;i<lenb;i++) dp[i][0]=0; for(i=0;i<lena;i++) for(j=0;j<lenb;j++) dp[i+1][j+1]=a[i]==b[j]?dp[i][j]+1:(dp[i+1][j]>dp[i][j+1]?dp[i+1][j]:dp[i][j+1]); printf("%d\n",dp[lena][lenb]); } } //刘汝佳的空间O(m)算法 #include <iostream> using namespace std; inline int max(int a,int b) { return a>b?a:b; } int dp[2013]; char a[2013],b[2013]; int main() { int i,j,lena,lenb,x; while(~scanf("%s%s",a+1,b+1)) { x=0; lena=strlen(a+1); lenb=strlen(b+1); memset(dp,0,sizeof(dp)); for(i=1;i<=lena;i++) for(j=1;j<=lenb;j++) { if(a[i]==b[j]) dp[j]=dp[j-1]+1; else { if(i==j) dp[j]=x; else { x=dp[j]; dp[j]=max(dp[j-1],dp[j]); } } } printf("%d\n",dp[lenb]); } }
/* HOJ 1171 Big Event in HDU 01背包。改变数量(k)和金额(j)的循环顺序,边二分边减。时效46MS */ #include <iostream> using namespace std; int dp[250001]; int s[51]; int num[51]; int main() { int i,j,k,max,up,up2,n,t,tn; while(~scanf("%d",&n)) { if(n<0) continue; dp[up=max=0]=1; for(i=0;i<n;i++) { scanf("%d%d",s+i,num+i); up+=s[i]*num[i]; } up2=up/2; for(i=0;i<n;i++) { for(k=1;k<num[i];k*=2) { num[i]-=k; for(j=max;j>=0;j--) { if(dp[j]&&(t=j+s[i]*k)<=up2) { dp[t]=1; if(max<t) max=t; } } } { for(j=max;j>=0;j--) { if(dp[j]&&(t=j+s[i]*num[i])<=up2) { dp[t]=1; if(max<t) max=t; } } } } printf("%d %d\n",up-max,max); } }
/* HOJ 1224 Free DIY Tour */ #include <iostream> using namespace std; int d[150],map[150][150],a[150],line[150],n; void print(int x) { if(line[x]==-1) { printf("%d",1); return; } print(line[x]); printf("->%d",x); return; } int main() { int m,i,j,x,y,cas,k=1; scanf("%d",&cas); while(cas--) { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",a+i); a[++n]=0; scanf("%d",&m); memset(d,0,sizeof(d)); memset(map,0,sizeof(map)); memset(line,-1,sizeof(line)); for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); map[x][y]=1; } for(i=1;i<=n;i++) for(j=1;j<i;j++) { if(map[j][i]&&d[i]<d[j]+a[i]) { line[i]=j; d[i]=d[j]+a[i]; } } printf("CASE %d#\n",k++); printf("points : %d\n",d[n]); printf("circuit : "); print(line[n]); printf("->1\n"); if(cas) printf("\n"); } }
/* HOJ 1421 搬寝室 状态的理解。每对物品的只有两种状态,取,或不取。 状态转移:dp[i][j]=min(dp[i-2][j-1]+a[i],dp[i-1][j]) 另外,memset真心拖时间。。。 */ #include <iostream> using namespace std; const int Max=0x7FFFFFFF; int a[2012]; int dp[2013][2014]; inline int min(int a,int b) { return a<b?a:b; } int cmp(const void *a,const void *b) { return *(int *)b-*(int *)a; } int main() { int i,j,m,n; while(~scanf("%d%d",&n,&m)) { for(i=0;i<=n;i++) dp[i][0]=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) dp[i][j]=Max; for(i=1;i<=n;i++) scanf("%d",a+i); qsort(a+1,n,4,cmp); for(i=n;i>1;i--) a[i]=(a[i]-a[i-1])*(a[i]-a[i-1]); for(i=2;i<=n;i++) for(j=1;j*2<=i;j++) dp[i][j]=min(dp[i-2][j-1]+a[i],dp[i-1][j]); printf("%d\n",dp[n][m]); } }
/* HOJ 1422 重温世界杯 同MaxSum,状态有很多,但是发现当前状态sum<0,直接丢掉。。。 */ #include <iostream> using namespace std; int s[200000]; int main() { int i,j,m,n,t,sum,len,max; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) { scanf("%d%d",s+i,&t); s[i]-=t; s[n+i]=s[i]; } max=sum=len=0; m=n*2; for(i=1;i<=m;i++) { sum+=s[i]; if(sum<0) { len=0; sum=0; continue; } len++; if(len>max) { max=len; if(max>=n) break; } } printf("%d\n",max); } }
/* HOJ 1505 City Game DP.一开始真心没想到,原来和1506是一样的。。。即每行选取最大面积矩形,大于最大则更新。 */ #include <iostream> using namespace std; int h[1002],l[1002],r[1002]; int main() { char s[100]; int cas,i,j,m,n,ans,k,t; cin>>cas; while(cas--) { scanf("%d%d",&n,&m); ans=0; memset(h,0,4*(m+2)); for(i=0;i<n;i++) { for(j=1;j<=m;j++) { scanf("%s",s); if(s[0]=='F') h[j]++; else h[j]=0; } h[0]=h[m+1]=-1; for(j=1;j<=m;j++) { k=j-1; while(h[k]>=h[j]) k=l[k]; l[j]=k; } for(j=m;j>0;j--) { k=j+1; while(h[k]>=h[j]) k=r[k]; r[j]=k; } for(j=1;j<=m;j++) { t=(r[j]-l[j]-1)*h[j]; if(ans<t) ans=t; } } printf("%d\n",ans*3); } }
/* HOJ 1506 Largest Rectangle in a Histogram 动态规划 查找边界时可以保存当前边界值,可以方便下次的边界查找。 另外有注意的范围,用64位存储。 */ #include <iostream> using namespace std; int l[100002],r[100002]; long s[100002]; int main() { int i,j,n; __int64 max,t; while(scanf("%d",&n)&&n) { for(i=1;i<=n;i++) scanf("%ld",s+i); max=0; s[0]=s[n+1]=-1; for(i=1;i<=n;i++) { j=i-1; while(s[i]<=s[j]) j=l[j]; l[i]=j; } for(i=n;i>0;i--) { j=i+1; while(s[i]<=s[j]) j=r[j]; r[i]=j; } for(i=1;i<=n;i++) { t=(__int64)(r[i]-l[i]-1)*s[i]; if(max<t) max=t; } printf("%I64d\n",max); } }
/* HOJ 1864 最大报销额 01背包问题 */ #include <iostream> using namespace std; int s[3000001]; int main() { char a,b; double t,sum,money[3]; int up,i,j,n,m,flag,max,temp; while(~scanf("%lf%d",&t,&n)&&n) { up=(int)(t*100); memset(s,0,sizeof(s)); s[0]=1; max=0; for(i=0;i<n;i++) { sum=0; money[0]=money[1]=money[2]=0; flag=1; scanf("%d",&m); for(j=0;j<m;j++) { scanf("%c%c%c%lf",&b,&a,&b,&t); if(flag) { if(a>'C'||a<'A'||t>600) flag=0; else { money[a-'A']+=t; sum+=t; if(sum>1000||money[a-'A']>600) flag=0; } } } if(flag) for(j=max;j>=0;j--) if(s[j]) { s[temp=j+(int)(sum*100)]=1; if(temp>max&&temp<=up) max=temp; } } printf("%d.%02d\n",max/100,max%100); } }
/* HOJ 2059 龟兔赛跑 */ #include <iostream> using namespace std; int main() { int i,j,n,L,t,c,vr,vc,vt,s[102]; double up,m,Min,d[102],len; while(~scanf("%d",&L)) { scanf("%d%d%d%d%d%d",&n,&c,&t,&vr,&vc,&vt); for(i=1;i<=n;i++) scanf("%d",s+i); s[++n]=L; up=(L*1.0)/vr; m=0; d[0]=s[0]=0; for(i=1;i<=n;i++) { Min=0x7FFFFFFF; for(j=0;j<i;j++) { len=s[i]-s[j]; m=c>len?(1.0*len/vc):(1.0*c/vc+1.0*(len-c)/vt); m+=d[j]; if(j) m+=t; if(Min>m) Min=m; } d[i]=Min; } if(d[n]>up) printf("Good job,rabbit!\n"); else printf("What a pity rabbit!\n"); } }
/* HOJ 2159 FATE 二维01背包 */ #include <iostream> using namespace std; int v[101],c[101],dp[101][101]; int n,m,k,s,t; void tpack(int cost1,int cost2,int weight) { for(int i=cost1;i<=m;i++) for(int j=cost2;j<=s;j++) if(dp[i][j]<(t=dp[i-cost1][j-cost2]+weight)) dp[i][j]=t; } int main() { while(cin>>n>>m>>k>>s) { memset(dp,0,sizeof(dp)); for(int i=0;i<k;i++) { cin>>v[i]>>c[i]; tpack(c[i],1,v[i]); } if(dp[m][s]<n) { cout<<-1<<endl; continue; } int min=0x7FFFFFFE; for(int i=0;i<=m;i++) for(int j=0;j<=s;j++) if(dp[i][j]>=n&&min>i) min=i; cout<<m-min<<endl; } }
/* HOJ 2577 How to Type */ #include <iostream> using namespace std; int on[101],off[101]; char s[100]; inline int min(int a,int b) { return a<b?a:b; } int main() { int i,len,cas; cin>>cas; while(cas--) { scanf("%s",s); on[0]=off[0]=2; if(s[0]>='a') off[0]=1; len=strlen(s); for(i=1;i<len;i++) { if(s[i]>='a') { on[i]=min(on[i-1]+2,off[i-1]+2); off[i]=min(on[i-1]+2,off[i-1]+1); } else { on[i]=min(on[i-1]+1,off[i-1]+2); off[i]=min(on[i-1]+2,off[i-1]+2); } } printf("%d\n",min(on[i-1]+1,off[i-1])); } }
/* HOJ 2830 Matrix Swapping II 求正数的最大值就是求负数的最小值。。。这样写貌似比较简洁 */ #include <iostream> #include <algorithm> using namespace std; char str[1001]; int s[1001],a[1001]; int cmp(const void* a,const void* b) { return *(int *)a-*(int *)b; } int main() { int m,n,i,j,t,min; while(~scanf("%d%d",&n,&m)) { for(j=0;j<=m;j++) s[j]=0; min=0; for(i=1;i<=n;i++) { scanf("%s",str+1); for(j=1;j<=m;j++) if(str[j]=='0') s[j]=0; else s[j]--; for(j=1;j<=m;j++) a[j]=s[j]; qsort(a+1,m,sizeof(int),cmp); for(j=1;j<=m;j++) if(min>(t=j*a[j])) min=t; } printf("%d\n",-min); } }
/* HOJ 2844 Coins */ #include <iostream> using namespace std; int c[101],v[101],dp[100001],num[101],V; inline int max(int a,int b) { return a>b?a:b; } void zpack(int cost,int weight) { for(int i=V;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } void cpack(int cost,int weight) { for(int i=cost;i<=V;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } void mpack(int cost,int weight,int amount) { if(amount*cost>=V) { cpack(cost,weight); return; } for(int k=1;k<amount;k*=2) { amount-=k; zpack(cost*k,weight*k); } zpack(cost*amount,weight*amount); } int main() { int i,j,n,ans; while(scanf("%d%d",&n,&V),n|V) { ans=0; for(i=0;i<=V;i++) dp[i]=0; for(i=0;i<n;i++) scanf("%d",v+i); for(i=0;i<n;i++) scanf("%d",num+i); for(i=0;i<n;i++) mpack(v[i],v[i],num[i]); for(i=1;i<=V;i++) if(dp[i]==i) ans++; printf("%d\n",ans); } }
/* HOJ 2845 Beans 搬寝室的平方。。。每次取每行最大和,最后取每列的最大和 */ #include <iostream> using namespace std; int a[200001],b[200001]; int max(int a,int b) { return a>b?a:b; } int main() { int m,n,i,j,t; a[0]=0; while(~scanf("%d%d",&n,&m)) { for(i=1;i<=n;i++) { scanf("%d",a+1); for(j=2;j<=m;j++) { scanf("%d",&t); a[j]=max(a[j-2]+t,a[j-1]); } b[i]=a[m]; } a[1]=b[1]; for(i=2;i<=n;i++) a[i]=max(a[i-2]+b[i],a[i-1]); printf("%d\n",a[n]); } }
/* HOJ 2870 Largest Submatrix 3 X CityGames.记录a,b,c三个数组,每次查找边界求最大面积。 */ #include <iostream> using namespace std; int ch[3][1001],l[1001],r[1001]; int main() { char s[1001]; int m,n,i,j,k,h,Max,t; while(~scanf("%d%d",&n,&m)) { Max=0; for(i=0;i<=m;i++) ch[0][i]=ch[1][i]=ch[2][i]=0; for(i=1;i<=n;i++) { scanf("%s",s+1); for(j=1;j<=m;j++) { switch(s[j]) { case 'a': { ch[0][j]++; ch[1][j]=0; ch[2][j]=0; break; } case 'b': { ch[0][j]=0; ch[1][j]++; ch[2][j]=0; break; } case 'c': { ch[0][j]=0; ch[1][j]=0; ch[2][j]++; break; } case 'w': { ch[0][j]++; ch[1][j]++; ch[2][j]=0; break; } case 'x': { ch[0][j]=0; ch[1][j]++; ch[2][j]++; break; } case 'y': { ch[0][j]++; ch[1][j]=0; ch[2][j]++; break; } case 'z': { ch[0][j]++; ch[1][j]++; ch[2][j]++; break; } } } for(h=0;h<3;h++) { ch[h][0]=ch[h][m+1]=-1; for(j=1;j<=m;j++) { k=j-1; while(ch[h][k]>=ch[h][j]) k=l[k]; l[j]=k; } for(j=m;j>=1;j--) { k=j+1; while(ch[h][k]>=ch[h][j]) k=r[k]; r[j]=k; } for(j=1;j<=m;j++) { if(Max<(t=(r[j]-l[j]-1)*ch[h][j])) Max=t; } } } printf("%d\n",Max); } }