poj3624
0-1背包 裸
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 const int maxn=15000; 6 int w[maxn]; 7 int v[maxn]; 8 int cost; 9 int main() 10 { 11 int n,m; 12 scanf("%d%d",&n,&cost); 13 for(int i=0;i<n;i++) 14 { 15 scanf("%d%d",&w[i],&v[i]); 16 } 17 int dp[maxn]; 18 memset(dp,0,sizeof(dp)); 19 for(int i=0;i<n;i++) 20 { 21 for(int j=cost;j>=w[i];j--) 22 { 23 dp[j]=max(dp[j],dp[j-w[i]]+v[i]); 24 } 25 } 26 cout<<dp[cost]<<endl; 27 }
poj3628
2^20 枚举即可
1 #include<iostream> 2 #include<stdio.h> 3 #include<cstring> 4 #include<vector> 5 6 using namespace std; 7 8 int a[22]; 9 int n,m; 10 11 12 int cal(int x) 13 { 14 int i=0; 15 int sum=0; 16 while(x) 17 { 18 if(x&1) sum+=a[i]; 19 x>>=1; 20 i++; 21 } 22 return sum; 23 } 24 25 26 int main() 27 { 28 scanf("%d%d",&n,&m); 29 for(int i=0;i<n;i++) 30 scanf("%d",&a[i]); 31 32 int num=2e9; 33 34 for(int i=0;i<=(1<<n)-1;i++) 35 { 36 int d=cal(i); 37 if(d<num&&d>=m) num=d; 38 } 39 printf("%d ",num-m); 40 }
方法2: 0-1背包 用所有cow的高度和作为背包体积V,最后找到最小的但是大于m的即可,背包体积从小到大枚举找到ans
#include<iostream> #include<stdio.h> #include<cstring> #include<vector> using namespace std; int dp[20000005]; int a[22]; int main() { int n,m; scanf("%d%d",&n,&m); int sum=0; for(int i=0;i<n;i++) scanf("%d",&a[i]),sum+=a[i]; dp[0]=0; for(int i=0;i<n;i++) { for(int j=sum;j>=a[i];j--) dp[j]=max(dp[j],dp[j-a[i]]+a[i]); } for(int i=0;i<=sum;i++) { if(dp[i]>=m) {printf("%d ",dp[i]-m);break;} } }
poj 1837
题意:背包变形,在一个天平上有一些挂钩 一些砝码,将所有砝码挂上去,问使得天平平衡的方案数是多少?
思路:类似背包 这里使用7500作平衡点,另外dp[i][j]表示前i个砝码都放上去,平衡度为j时的方案数目,引入平衡度的概念。那么dp[i][j]=sigma(dp[i-1][j-c[k]*w[i]]),0<=k<n, ans=dp[m][7500];
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m; int w[50]; int c[50]; int dp[22][15010]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<=m;i++) scanf("%d",&w[i]); memset(dp,0,sizeof(dp)); dp[0][7500]=1; for(int i=1;i<=m;i++) { for(int j=0;j<=15000;j++) { for(int k=1;k<=n;k++) { dp[i][j]+=dp[i-1][j-c[k]*w[i]]; //dp[i][j+c[k]*w[i]]+=dp[i-1][j]; } } } printf("%d ",dp[m][7500]); }
hdu 2548 饭卡
思路:如果余额小于5元,就直接输出余额,如果余额大于五元就直接留出来买最贵的那个,然后去掉五元之外的钱,用来做0-1背包,买其他的物品
#include<bits/stdc++.h> using namespace std; int w[1010]; int dp[50000+100]; int t; int cost; int n; int main() { while(~scanf("%d",&n)&&n) { for(int i=0;i<n;i++) scanf("%d",&w[i]); scanf("%d",&cost); if(cost<5) {printf("%d ",cost);continue;} sort(w,w+n); cost-=5; memset(dp,0,sizeof(dp)); for(int i=0;i<n-1;i++) { for(int j=cost;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+w[i]); } printf("%d ",cost-dp[cost]+5-w[n-1]); } return 0; }
poj 3903 nlog(n)求最长递增子序列LIS
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 6 using namespace std; 7 8 int n; 9 const int maxn=100010; 10 const int inf=0x7fffffff; 11 int dp[maxn]; 12 int a[maxn]; 13 14 int main() 15 { 16 while(~scanf("%d",&n)) 17 { 18 for(int i=0;i<n;i++) scanf("%d",&a[i]); 19 20 fill(dp,dp+n,inf); 21 22 for(int i=0;i<n;i++) 23 *lower_bound(dp,dp+n,a[i])=a[i]; 24 int ans=lower_bound(dp,dp+n,inf)-dp; 25 printf("%d ",ans); 26 } 27 }
hdu 1203 0-1背包变形
题意:qn要去申请n所学校,但是只有cost前,每所学校都有申请费用以及录取概率,求qn有学上的最大概率
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 double dp[10010]; 6 int w[10010]; 7 double p[10010]; 8 int n,cost; 9 10 double cal(double x,double y) 11 { 12 double c=1.0-(1-x)*(1-y); 13 return c; 14 } 15 16 int main() 17 { 18 while(~scanf("%d%d",&cost,&n)&&(cost||n)) 19 { 20 for(int i=0;i<n;i++) 21 scanf("%d%lf",&w[i],&p[i]); 22 memset(dp,0,sizeof(dp)); 23 for(int i=0;i<n;i++) 24 { 25 for(int j=cost;j>=w[i];j--) 26 dp[j]=max(dp[j],cal(dp[j-w[i]],p[i])); 27 } 28 printf("%.1f%% ",dp[cost]*100); 29 } 30 }
hdu 2955
题目大意:rob计划要抢银行,一共有n个银行,给定逃跑概率上限值lim(安全概率),对每个银行都有一个可以抢的钱数以及被抓的概率,问你在保证安全情况下,最多抢到多少钱?
思路:这题从被抓概率考虑,我们肯定要求最小的,这样就违背了背包的原理,我们反过来,从逃跑概率出发,也就是说求逃跑概率最大值满足条件,我们把抢到的钱看做体积,逃跑概率看做价值,这样背包之后,再从末尾往前查满足条件的即可,需要注意的是边界要进行初始化,0的时候 就是不抢 概率为1 ,同时还要注意一定要恰好装满背包 需要重复查一次
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int t; 5 int n; 6 int cost; 7 double lim; 8 int w[110]; 9 double p[110]; 10 11 double dp[10010]; 12 13 double cal(double x,double y) 14 { 15 return x*y; 16 } 17 int main() 18 { 19 scanf("%d",&t); 20 while(t--) 21 { 22 cost=0; 23 scanf("%lf%d",&lim,&n); 24 lim=1-lim; 25 for(int i=0;i<n;i++) 26 scanf("%d%lf",&w[i],&p[i]),cost+=w[i],p[i]=1-p[i]; 27 memset(dp,0,sizeof(dp)); 28 dp[0]=1; 29 30 for(int i=0;i<n;i++) 31 { 32 for(int j=cost;j>=w[i];j--) 33 { 34 dp[j]=max(dp[j],cal(dp[j-w[i]],p[i])); 35 } 36 } 37 38 int ans; 39 for(int i=cost;i>=0;i--) 40 { 41 if(dp[i]>=lim) { 42 ans=i; 43 break; 44 } 45 } 46 int pos=0; 47 for(int i=ans;i>=1;i--) 48 { 49 if(dp[i]!=dp[i-1]){ 50 pos=i; 51 break; 52 } 53 } 54 55 printf("%d ",pos); 56 } 57 }
poj 1948 Triangular Pastures 子集和问题
题目大意:有n个木棒,给出每个木棒的长度,将所有三角形都用上,求所能构成的三角形的最大面积,最后结果乘以100 向下取整,若不能构成三角形 输出-1;
题目思路,dp[i][j][k]表示前i个木棒能不能拼成两条边的长度分别为j和k,那么第三条边就可以减法求出来
dp[i][j][k]=(dp[i-1][j][k]|dp[i-1][j-w[i]][k]|dp[i-1][j][k-w[i]]); 由于内存限制,优化掉第一层,滚动数组
1 #include<iostream> 2 #include<stdio.h> 3 #include<cstring> 4 #include<cmath> 5 6 using namespace std; 7 8 int n; 9 int w[50]; 10 bool dp[1610][1610]; 11 12 double cal(double p,int a,int b,int c) 13 { 14 return sqrt(double(p*1.0*(p-a)*(p-b)*(p-c))); 15 } 16 17 18 19 int main() 20 { 21 scanf("%d",&n); 22 int sum=0; 23 for(int i=0;i<n;i++) 24 scanf("%d",&w[i]),sum+=w[i]; 25 memset(dp,0,sizeof(dp)); 26 dp[w[0]][0]=dp[0][w[0]]=1; 27 28 double ans=0; 29 30 int flag=0; 31 32 for(int i=1;i<n;i++) 33 { 34 for(int j=sum;j>=0;j--) 35 { 36 for(int k=sum;k>=0;k--) 37 { 38 if(j-w[i]>=0) dp[j][k]|=dp[j-w[i]][k]; 39 if(k-w[i]>=0) dp[j][k]|=dp[j][k-w[i]]; 40 int c=sum-j-k; 41 if(dp[j][k]&&j+k>c&&j+c>k&&k+c>j){ 42 ans=max(ans,cal(sum/2.0,j,k,c)); 43 flag=1; 44 } 45 } 46 } 47 } 48 if(flag) 49 printf("%d ",int(ans*100)); 50 else puts("-1"); 51 52 }
A
题目大意:有一个十字路口的交通灯,给出各种左转,右转,直行,人行横道,判断是否会撞到人行横道
思路:分别对直行、左转、右转进行判断即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int l[4]; 5 int s[4]; 6 int r[4]; 7 int p[4]; 8 9 int main() 10 { 11 for(int i=0;i<4;i++) 12 cin>>l[i]>>s[i]>>r[i]>>p[i]; 13 for(int i=0;i<4;i++) 14 { 15 if((l[i]||r[i]||s[i])&&p[i]){ 16 cout<<"YES";return 0; 17 } 18 } 19 for(int i=0;i<4;i++) 20 { 21 if(r[i]&&p[(i+1)%4]){ 22 cout<<"YES";return 0; 23 } 24 } 25 for(int i=0;i<4;i++) 26 { 27 if(l[i]&&p[(i+4-1)%4]){ 28 cout<<"YES";return 0; 29 } 30 } 31 for(int i=0;i<4;i++) 32 { 33 if(s[i]&&p[(i+2)%4]) 34 { 35 cout<<"YES";return 0; 36 } 37 } 38 cout<<"NO"; 39 return 0; 40 }
B
题目大意:一个矩阵,最左右两列表示楼梯,中间的m列表示灯,走一步需要1min,每次关完本层的灯,再去关上层的灯,从左下角出发,求关完所有的灯需要的时间
思路:
预处理一下,对每一层从左边或者右边出发 需要花费多少时间,进行二进制枚举每一层从左边走还是右边走,用pre保存下一层从左边走的还是从右边走的,然后进行枚举求最小值,
注意两个地方:
一是注意预处理一下需要走上第几层,二是不需要向上走时,就不用再动了,二进制枚举右移次数有限制
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n,m; 5 int ma[20][110]; 6 int l[20]; 7 int r[20]; 8 const int inf=0x7fffffff; 9 10 11 int main() 12 { 13 memset(l,0,sizeof(l)); 14 memset(r,0,sizeof(r)); 15 char c; 16 cin>>n>>m; 17 for(int i=0;i<n;i++) 18 { 19 for(int j=0;j<m+2;j++) 20 { 21 cin>>c; 22 ma[i][j]=c-'0'; 23 } 24 } 25 for(int i=n-1;i>=0;i--) 26 { 27 for(int j=0;j<m+2;j++) 28 { 29 if(ma[i][j]==1){ 30 l[i]=max(l[i],j); 31 r[i]=max(r[i],m+1-j); 32 } 33 } 34 } 35 36 int flag=n-1; 37 for(int i=0;i<n;i++) 38 { 39 if(l[i]) {flag=i;break;} 40 } 41 42 int ans=inf; 43 for(int i=0;i<=(1<<(n-1))-1;i++) 44 { 45 int p=i; 46 int sum=0; 47 int pre=0; 48 for(int j=n-2,k=0;j>=0&&k<n-1-flag;j--,k++) 49 { 50 if(p&1){ 51 if(pre){ 52 sum+=r[j+1]+r[j]; 53 pre=1; 54 } 55 else { 56 sum+=(m+1-l[j+1])+r[j]; 57 pre=1; 58 } 59 } 60 else{ 61 if(pre){ 62 sum+=(m+1-r[j+1])+l[j]; 63 pre=0; 64 } 65 else { 66 sum+=l[j+1]+l[j]; 67 pre=0; 68 } 69 } 70 p>>=1; 71 } 72 sum+=l[n-1]; 73 sum+=n-1-flag; 74 75 ans=min(ans,sum); 76 } 77 cout<<ans; 78 }
C
简单二分,
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 int n,cost; 7 struct node 8 { 9 int v; 10 int ord; 11 LL cal; 12 }a[100000+100]; 13 const int inf=0x7fffffff; 14 LL num=inf; 15 16 int cmp(node u,node v) 17 { 18 if(u.cal<v.cal) return 1; 19 else return 0; 20 } 21 22 int check(int x) 23 { 24 LL sum=0; 25 for(int i=1;i<=n;i++) 26 { 27 a[i].cal=a[i].ord*1LL*x+a[i].v; 28 } 29 sort(a+1,a+n+1,cmp); 30 for(int i=1;i<=x;i++) 31 { 32 sum+=a[i].cal; 33 if(sum>cost*1LL) return 0; 34 } 35 36 37 38 num=sum; 39 40 return 1; 41 } 42 43 44 int main() 45 { 46 scanf("%d%d",&n,&cost); 47 for(int i=1;i<=n;i++) 48 { 49 scanf("%d",&a[i].v); 50 a[i].ord=i; 51 } 52 int l=0,r=n; 53 int ans=0; 54 while(l<=r) 55 { 56 57 int mid=(l+r)/2; 58 if(check(mid)) { 59 ans=mid; 60 l=mid+1; 61 } 62 else { 63 r=mid-1; 64 } 65 } 66 printf("%d %I64d ",ans,num); 67 }