POJ 1014 Dividing
这道题用背包做有两种解法,一种是拆分法,另一种是很神的O(VN)的DP法。
拆分法:
#include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define MAXN 10005 #define INF 100000000 #define eps 1e-11 #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; int f[240005], v; void complete_pack(int *a, int c, int w) { for(int i = c; i <= v; i++) a[i] = max(a[i], a[i - c] + w); } void zeroone_pack(int *a, int c, int w) { for(int i = v; i >= c; i--) a[i] = max(a[i], a[i - c] + w); } void mutiple_pack(int *a, int c, int w, int M) { if(c * M >= v) { complete_pack(a, c, w); return; } int k = 1; while(k < M) { zeroone_pack(a, k * c, k * w); M = M - k; k = 2 * k; } zeroone_pack(a, c * M, w * M); } int main() { //freopen("d:/data.in","r",stdin); //freopen("d:/data.out","w",stdout); int sum, i, c[7], w[7], m[7],cas = 0; while(scanf("%d%d%d%d%d%d", &m[1], &m[2], &m[3], &m[4], &m[5], &m[6])) { if(m[1] == 0 && m[2] == 0 && m[3] == 0 && m[4] == 0 && m[5] == 0 && m[6] == 0) break; sum = 0; for(i = 1; i <= 6; i++) { c[i] = w[i] = i; sum += c[i] * m[i]; } printf("Collection #%d:\n", ++cas); if(sum & 1) { puts("Can't be divided.\n"); } else { sum /= 2; for(i = 1; i <= sum; i++) f[i] = -INF; f[0] = 0; v = sum; for(i = 1; i <= 6; i++) mutiple_pack(f, c[i], w[i], m[i]); if(f[v] < 0) { puts("Can't be divided.\n"); } else { puts("Can be divided.\n"); } } } return 0; }POJ 1742Coins
很裸的背包可行性问题
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 10005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
bool f[100005];
int used[100005];
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int n, m, v[105], num[105], i, j;
while(scanf("%d%d", &n, &m) != EOF)
{
if(n == 0 && m == 0) break;
for(i = 1; i <= n; i++)
scanf("%d", &v[i]);
for(i = 1; i <= n; i++)
scanf("%d", &num[i]);
memset(f, 0, sizeof(f));
f[0] = 1;
int sum = 0;
for(i = 1; i <= n; i++)
{
memset(used, 0, sizeof(used));
for(j = v[i]; j <= m; j++)
{
if(!f[j] && f[j - v[i]] && used[j - v[i]] + 1 <= num[i])
{
f[j] = 1;
used[j] = used[j - v[i]] + 1;
sum++;
}
}
}
printf("%d\n", sum);
}
return 0;
}
POJ 2392 Space Elevator
这个题的多了一个限制条件,实际上只要按限制条件从小到大排序就行
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 10005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct wwj
{
int h, num, a;
}p[405];
bool f[400005];
int used[400005];
bool cmp(wwj x, wwj y)
{
return x.a < y.a;
}
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int k, i, j;
scanf("%d", &k);
for(i = 1; i <= k; i++)
{
scanf("%d%d%d", &p[i].h, &p[i].a, &p[i].num);
}
sort(p + 1, p + k + 1, cmp);
memset(f, 0, sizeof(f));
f[0] = 1;
int ans = 0;
for(i = 1; i <= k; i++)
{
memset(used, 0, sizeof(used));
for(j = p[i].h; j <= p[i].a; j++)
{
if(!f[j] && f[j - p[i].h] && used[j - p[i].h] + 1 <= p[i].num)
{
f[j] = 1;
used[j] = used[j - p[i].h] + 1;
ans = max(j, ans);
}
}
}
printf("%d\n", ans);
return 0;
}
POJ 1276Cash Machine
裸题不解释
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 10005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
bool f[100005];
int used[100005];
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int cash, i, j, n, num[1005], v[1005];
while(scanf("%d", &cash) != EOF)
{
scanf("%d", &n);
for(i = 1; i <= n; i++)
scanf("%d%d", &num[i], &v[i]);
memset(f, 0, sizeof(f));
f[0] = 1;
int ans = 0;
for(i = 1; i <= n; i++)
{
memset(used, 0, sizeof(used));
for(j = v[i]; j <= cash; j++)
{
if(!f[j] && f[j - v[i]] && used[j - v[i]] + 1 <= num[i])
{
f[j] = 1;
used[j] = used[j - v[i]] + 1;
ans = max(ans, j);
}
}
}
printf("%d\n", ans);
}
return 0;
}
POJ 3211Washing Clothes
其实就是个0-1背包变形,对同种颜色的衣服,把一个人洗所有衣服的时间算出来,除以二,然后看能达到的最大容量,这就可以保证两人的洗衣时间尽量平均了。也可以用多重背包的做法做,只要把件数都设成1就行。
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 10005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
bool f[50005];
int v[11][101], cnt[11];
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int n, m, i, j, x, k;
char s[22];
while(scanf("%d%d", &n, &m) != EOF)
{
if(n == 0 && m == 0) break;
map<string, int>mp;
memset(cnt, 0, sizeof(cnt));
for(i = 1; i <= n; i++)
{
scanf("%s", s);
string tmp = s;
mp[tmp] = i;
}
for(i = 1; i <= m; i++)
{
scanf("%d%s", &x, s);
string tmp = s;
cnt[mp[tmp]]++;
v[mp[tmp]][cnt[mp[tmp]]] = x;
}
int ans = 0;
int mx;
for(i = 1; i <= n; i++)
{
int sum = 0;
mx = 0;
for(j = 1; j <= cnt[i]; j++)
sum += v[i][j];
for(j = 0; j <= sum / 2; j++)
f[j] = 0;
f[0] = 1;
for(j = 1; j <= cnt[i]; j++)
{
for(k = sum / 2; k >= v[i][j]; k--) //倒序的0-1背包做法
{
if(!f[k] && f[k - v[i][j]] )
{
f[k] = 1;
mx = max(mx, k);
}
}
/* 多重背包做法
for(k = 0; k <= sum / 2; k++)
used[k] = 0;
for(k = v[i][j]; k <= sum / 2; k++)
{
if(!f[k] && f[k - v[i][j]] && !used[k - v[i][j]])
{
used[k] = 1;
f[k] = 1;
mx = max(mx, k);
}
}
*/
}
ans += (sum - mx);
}
printf("%d\n", ans);
}
return 0;
}