【常規的01揹包 POJ3624 UVA562 HDU2546 HDU3466 poj1745】
阿新 • • 發佈:2018-12-05
POJ3624
有N個物品,分別有不同的重量Wi和價值Di,Bessie只能帶走重量不超過M的物品,要是總價值最大,並輸出總價值
//#include <bits/stdc++.h> #include <iostream> #define X 10005 #define inf 0x3f3f3f3f #define PI 3.141592653589793238462643383 #define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0); #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long ll; const int maxn=1e6+10; using namespace std; int dp[maxn]; int c[maxn]; int w[maxn]; int main() { int n,m; while(cin>>n>>m) { for(int i=0; i<n; ++i){cin>>c[i]>>w[i];} for(int i=0; i<n; ++i) for(int j=m; j>=c[i]; --j) dp[j]=max(dp[j],dp[j-c[i]]+w[i]); cout<<dp[m]<<endl; } return 0; }
UVA562
給定n個硬幣,要求將這些硬幣平分以使兩個人獲得的錢儘量多,求兩個人分到的錢最小差值。
#include <bits/stdc++.h> #include <iostream> #define X 10005 #define inf 0x3f3f3f3f #define PI 3.141592653589793238462643383 #define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0); #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long ll; const ll moad=1e9+7; const int maxn=1e6+10; int dp[maxn]; int w[maxn]; int vis[maxn]; int main() { int t,n; cin>>t; while(t--) { cin>>n; int sum=0; for(int i=0;i<n;++i)cin>>w[i],sum+=w[i]; memset(dp,0,sizeof(dp)); for(int i=0;i<n;++i) { for(int j=sum/2;j>=w[i];--j) { dp[j]=max(dp[j],dp[j-w[i]]+w[i]); } } int __=dp[sum/2],_; _=sum-__; cout<<abs(__-_)<<endl; } return 0; }
HDU2546
這題看上去就知道是01問題了,可是開始怎麼轉化都沒有轉化為正確的01揹包姿勢
因為沒有明顯的給出來一個揹包的容量(做完之後,看出來其實是給出來的,就是這個m-5),然後我wa的姿勢是找所有物品的價值總和去作為容量
撒了一眼題解看是m-5,才知道可以用這個-5剩下的錢去01揹包買更多的東西,最後加上那個5塊錢去買加個最大的物品
這個5塊好像用到了貪心的思想 mmp
總結:轉化為正確的01問題姿勢是關鍵
#include <bits/stdc++.h> #include <iostream> #define X 10005 #define inf 0x3f3f3f3f #define PI 3.141592653589793238462643383 #define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0); #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=1e6+10; int dp[maxn]; int w[1005]; int main() { int n,m; while(cin>>n,n) { memset(dp,0,sizeof(dp)); for(int i=0;i<n;++i) cin>>w[i]; cin>>m; if(m<5){cout<<m<<endl;continue;} sort(w,w+n); int _now=m-5; for(int i=0;i<n-1;++i) { for(int j=_now;j>=w[i];--j) dp[j]=max(dp[j],dp[j-w[i]]+w[i]); } cout<<m-(w[n-1]+dp[_now])<<endl; } return 0; }
#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+10;
int dp[maxn];
int w[1005];
int main()
{
int n,m;
while(cin>>n,n)
{
int ans=0;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i) cin>>w[i],ans+=w[i];
cin>>m;
if(m<5){cout<<m<<endl;continue;}
for(int i=0;i<n;++i)
{
for(int j=ans;j>=w[i];--j)
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
}
cout<<m-dp[ans]<<endl;
}
return 0;
}
HDU3466
先前得01揹包問題都是佔用多大空間,有多大空間就可以直接進行放入,而這個有個限制體條件
當容量低於特定值得時候就不可以放入,那這樣進行放入得原則就是 需要的容量/本身佔有得容量大小 這個值越小越好,所謂得價效比越高越好嘛
還有要注意的一點就是當 揹包容量小於給的特定值得時候就不可以進行更新dp陣列了
#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const ll moad=1e9+7;
const int maxn=1e6+10;
int q[maxn];
int c[maxn];
int w[maxn];
int dp[maxn];
struct node
{
double c,q,w;
}point[maxn];
bool cmp(node a,node b)
{
//return a.q-a.c<b.q-b.c;
//return a.c*b.q<b.c*a.q;
return a.q/a.c<=b.q/b.c;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i)cin>>point[i].c>>point[i].q>>point[i].w;
sort(point,point+n,cmp);
// for(int i=0;i<n;++i)
// cout<<point[i].c<<' '<<point[i].q<<' '<<point[i].w<<endl;
for(int i=0;i<n;++i)
{
for(int j=m;j>=point[i].q;--j)
{
dp[j]=max(dp[j],dp[j-int(point[i].c)]+int(point[i].w));
}
}
cout<<dp[m]<<endl;
}
return 0;
}
poj1745
給你n個數,經過加減的操作,看能不能整除K。
dp[i][j]代表前i個數字整除 m 的餘數為 j
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define X 10005
using namespace std;
int main()
{
int N,K;
cin>>N>>K;
int a[X];
for(int i=1;i<=N;++i)
{
scanf("%d",&a[i]);
a[i]%=K;
}
int dp[X][K];
memset(dp,0,sizeof(dp));
//if(a[1]<0)
// a[1]+=K;
a[1]=(a[1]+K)%K;
dp[1][a[1]]=1;
for(int i=2;i<=N;++i)
{
for(int j=0;j<K;++j)
{
if(dp[i-1][j])
{
/* if(j+a[i]>=0)
dp[i][j+a[i]]=1;
else
dp[i][j+a[i]+K]=1;
if(j>=a[i])
dp[i][j-a[i]]=1;
else
dp[i][j-a[i]+K]=1;*/
dp[i][(j+a[i]+K)%K]=1;//保證下標大於0
dp[i][(j-a[i]+K)%K]=1;
}
}
}
if(dp[N][0])
cout<<"Divisible"<<endl;
else
cout<<"Not divisible"<<endl;
return 0;
}
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define X 10005
using namespace std;
long long POW(int a,int b)
{
long long ans=1;
while(b){
if(b&1)
{
ans*=a;
}
a*=a;
b>>=1;
}
return ans;
}
int main()
{
int N,K;
cin>>N>>K;
int a[X];
for(int i=0;i<N;++i)
{
scanf("%d",&a[i]);
}
long long n=POW(2,N-1);
for(int i=0;i<n;++i)
{
int sum=a[0];//cout<<a[0];
for(int j=0;j<N-1;++j)
{
if((i>>j)&1)
{//cout<<'-'<<a[j+1];
sum+=a[j+1];
}
else
sum-=a[j+1];//,cout<<'+'<<a[j+1];
}
//cout<<'='<<sum<<"*****"<<sum%K<<endl;
if(!(sum%K))//!的優先順序比%的高
{
cout<<"Divisible"<<endl;
return 0;
}
//cout<<endl;
}
cout<<"Not divisible"<<endl;
return 0;
}
//這個方法是對的,可是在這兒N是10000算出來的n是2^10000會炸的