1、hdu 1260 Tickets

  题意:有k个人,售票员可以选择一个人卖,或者同时卖给相邻的两个人。问最少的售票时间。

  思路:dp[i] = min(dp[i - 1] + singlep[i], dp[i - 2] + dbp[i - 1]);dp[i]表示卖到第i个人后所需最少时间。注意时间为12小时制。

 #include<iostream>
#include<memory.h>
#include<algorithm>
using namespace std;
int n, k;
const int maxk = ;
int dp[maxk];
int singlep[maxk];
int dbp[maxk];
int main()
{
scanf("%d", &n);
while (n--)
{
scanf("%d", &k);
for (int i = ; i <= k; i++) scanf("%d", &singlep[i]);
for (int i = ; i <= k - ; i++) scanf("%d", &dbp[i]);
memset(dp, , sizeof(dp));
for (int i = ; i <= k; i++)
{
if (i == )dp[i] = singlep[i];
else
{
dp[i] = min(dp[i - ] + singlep[i], dp[i - ] + dbp[i - ]);
}
}
int hh = ;
int mm = , ss = ;
hh += dp[k]/;
mm += dp[k]%/ ;
ss += dp[k] % ;
char t1[] = "am", t2[] = "pm";
printf("%02d:%02d:%02d %s\n", (hh<=?hh:hh-), mm, ss, (hh >= ? t2 : t1));
}
return ;
}

2、hdu 1160 FatMouse's Speed

  题意:给出若干只老鼠的重量和速度。要求找到一个最长的序列,里面每只老鼠重量严格递增,速度严格递减。

  思路:先按照速度递减排序,然后求重量递增的最长递增子序列。这里采用DP的方法,用pre数组记录前驱。

 #include<iostream>
#include<algorithm>
using namespace std;
const int maxn = ;
struct node
{
int w;
int v;
int id;
}mice[maxn];
int dp[maxn];
int pre[maxn];
bool Cmp(const node&a, const node&b)
{
return a.v > b.v;
}
void Print(int r,int num)
{
if (r != -)
{
Print(pre[r],num+);
printf("%d\n", mice[r].id);
}
else printf("%d\n", num);
}
int main()
{
int cnt = ;
while (~scanf("%d%d", &mice[cnt].w, &mice[cnt].v))
{
mice[cnt].id = cnt + ;
cnt++;
}
sort(mice, mice + cnt, Cmp);
for (int i = ; i < cnt; i++) dp[i] = , pre[i] = -;
int re = ,maxl=;
for (int i = ; i < cnt; i++)
{
int ans = ,pos=i;
for (int j = ; j < i; j++)
{
if (dp[j]+ > dp[i]&&mice[i].w > mice[j].w&&mice[i].v<mice[j].v)
{
dp[i] = dp[j] + ;
pre[i] = j;
pos = j;
}
}
if (dp[i] > maxl) maxl = dp[i], re = i;
}
Print(re,);
return ;
}

3、poj 1015 Jury Compromise

  题意:有n个候选的陪审团的人,需要从中选出m个人,使得这m个人的辩护方总分减去控诉方总分的差值最小,当最小的有多个时,选择辩护方总分加上控诉方总分最高的方案。

  思路:dp[i][j]表示选i个人、差值为j-fix中辩护方总分加上控诉方总分最高的方案。用pre[i][j]记录路径。细节见代码。

 #include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int dp[][];//dp(j, k)表示,取j 个候选人,使其辩控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案dp(j, k)”)的辩控和。
vector<int> path[][]; int main()
{
int times = ;
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
int subtraction[], _plus[];
int n, m, i, j, k;
while (~scanf("%d%d", &n, &m) && n && m)
{//一共有n个候选人,要选m个
for (i = ; i<m; ++i)//清空vector
for (j = ; j<; ++j)
path[i][j].clear();
memset(dp, -, sizeof(dp));
int d, p;
for (i = ; i < n; i++)
{
cin >> d >> p;//输入辩护方和控诉方的打分
subtraction[i] = d - p;//得到每个人的辩护方的分数-控诉方的分数
_plus[i] = d + p;//得到和
}
int fix = * m;//由于题目中辩控差的值k 可以为负数,而程序中数租下标不能为负数,所以,在程序中不妨将辩控差的值都加上修正值fix=400,以免下标为负数导致出错。
//为什么fix = 400?这是很显然的,m上限为20人,当20人的d均为0,p均为20时,会出现辨控差为 - 400。修正后回避下标负数问题,区间整体平移,从[-400, 400]映射到[0, 800]。
dp[][fix] = ;
for (k = ; k < n; k++)//顺序选择一个候选人
for (i = m - ; i >= ; i--)//进行逆推
{
for (j = ; j < * fix; j++)
{
if (dp[i][j] >= )
{
if (dp[i + ][j + subtraction[k]] <= dp[i][j] + _plus[k])
{//可行方案dp(j-1, x)能演化成方案dp(j, k)的必要条件是:存在某个候选人i,i 在方案dp(j-1, x)中没有被选上,且x+V(i) = k。在所有满足该必要条件的dp(j-1, x)中,选出 dp(j-1, x) + S(i) 的值最大的那个,那么方案dp(j-1, x)再加上候选人i,就演变成了方案 dp(j, k)。
//dp[i][j + d[k]] = max(dp[i][j + d[k]], dp[i-1][j] + s[k])
dp[i + ][j + subtraction[k]] = dp[i][j] + _plus[k];
path[i + ][j + subtraction[k]] = path[i][j];//每次更新都要把path全部复制过来,就是因为这个才用的vector
path[i + ][j + subtraction[k]].push_back(k);
}
}
}
}
//DP后,从第m行的dp(m, fix)开始往两边搜索最小|D-P| 即可,第一个不为dp[m][k]!=-1的位置k就是最小|D-P|的所在。
//D+P = dp(m, |D-P| ) ,|D-P|已知。
//那么D = (D + P + | D - P | ) / 2, P = (D + P - | D - P | ) / 2,计算D和P时注意修正值fix
for (i = ; dp[m][fix + i] == - && dp[m][fix - i] == -; i++);
int temp = (dp[m][fix + i] > dp[m][fix - i]) ? i : -i;
int sumD = (dp[m][fix + temp] + temp) / ;
int sumP = (dp[m][fix + temp] - temp) / ;
printf("Jury #%d\n", times++);
printf("Best jury has value %d for prosecution and value %d for defence:\n", sumD, sumP);
for (i = ; i < m; i++)
printf(" %d", path[m][fix + temp][i] + );
printf("\n\n"); }
return ;
}

4、hdu 1159 Common Subsequence

  题意:求两个字符串的最长公共子序列的长度。

  思路:DP模板题。dp[i][j]表示a[0]~a[i]和b[0]~b[j]的最长公共子序列的长度。dp[i][j]=dp[i-1][j-1]+1(当a[i]==b[j]);dp[i][j]=max(dp[i-1][j],dp[i][j-1])(当a[i]!=b[j])

 #include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxl = ;
char a[maxl];
char b[maxl];
int dp[maxl][maxl];
int main()
{
while (~scanf("%s%s", a, b))
{
int la = strlen(a);
int lb = strlen(b);
memset(dp, , sizeof(dp));
for (int i = ; i < la; i++)
{
for (int j = ; j < lb; j++)
{
if (a[i] == b[j])
{
if (i > && j > )dp[i][j] = dp[i - ][j - ] + ;
else dp[i][j] = ;
}
else
{
if(i>&&j>)dp[i][j] = max(dp[i - ][j], dp[i][j - ]);
else if (i > ) dp[i][j] = dp[i - ][j];
else if (j > ) dp[i][j] = dp[i][j - ];
else dp[i][j] = ;
}
}
}
printf("%d\n", dp[la - ][lb - ]);
}
return ;
}

5、poj 1661 Help Jimmy

  题意:“是男人就下一百层”的超级简化版。限制每次从平台跳下的最大高度差,求从给定的位置出发,到地面的最短时间。

  思路:dp[i][0]表示从第i层左侧跳到地面的最短时间,dp[i][1]表示从第i层右侧跳到地面的最短时间。从底向上DP,对于当前层i,从i-1层到第1层更新其最短时间。

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
int x1;//板子左侧
int x2;//板子右侧
int h;//所在高度
};
node op[];
int dp[][];
//dp[i][0]表示以i号平台左边为起点到地面的最短时间,dp[i][1]表示以i号平台右边为起点到地面的最短时间
bool cmp(node a, node b)
{//按高度从低到高
return a.h < b.h;
}
const int inf = 0x7f7f7f7f;
int main()
{
int t;
int n, x, y, maxn;
scanf("%d", &t);
while (t--)
{
scanf("%d%d%d%d", &n, &x, &y, &maxn);
for (int i = ; i <= n; i++)
{
scanf("%d%d%d", &op[i].x1, &op[i].x2, &op[i].h);
}
sort(op + , op + n + , cmp); // 0 左
// 1 右
dp[][] = dp[][] = op[].h;
op[n + ].x1 = op[n + ].x2 = x;
op[n + ].h = y;// op[n+1] 其实代表的是坐标(x,y),最高的开始跳的地方; for (int i = ; i <= n + ; i++)
{//从高度低的向上DP
dp[i][] = dp[i][] = inf;
int flag0 = ; // 用于标记左面端点
int flag1 = ; // 用于标记右面端点
int tmp;
for (int j = i - ; j>; j--) // 这里注意必须逆序,因为从上往下跳,有板子挡住的话就没法继续往下跳了。
{
if (op[i].h - op[j].h > maxn) continue;
if (op[j].x1 <= op[i].x1 && op[j].x2 >= op[i].x1 &&flag0 == )
{//可以从第i个平台的左侧跳到第j个平台上
tmp = min(dp[j][] - op[j].x1 + op[i].x1, dp[j][] - op[i].x1 + op[j].x2);
dp[i][] = min(dp[i][], tmp + op[i].h - op[j].h);
//tmp表示跳到第j个平台后向左或向右走到地面的时间的最小值
//tmp + op[i].h - op[j].h为再加上从第i个平台左侧跳到第j个平台所需要的时间
flag0 = ; // 表示已经不能继续往下跳了,因为已经有板子了
}
if (op[j].x1 <= op[i].x2 && op[j].x2 >= op[i].x2&&flag1 == )
{//可以从第i个平台的右侧跳到第j个平台上
tmp = min(dp[j][] - op[j].x1 + op[i].x2, dp[j][] - op[i].x2 + op[j].x2);
dp[i][] = min(dp[i][], tmp + op[i].h - op[j].h);
flag1 = ; // 道理同上
}
if (flag0 == && flag1 == )break;
}
if (flag0 == && op[i].h <= maxn)
{//平台i左侧下没有其他板子,并且距离地面的高度小于等于跳的高度
dp[i][] = min(dp[i][], op[i].h);
}
if (flag1 == && op[i].h <= maxn)
{//平台i右侧下没有其他板子,并且距离地面的高度小于等于跳的高度
dp[i][] = min(dp[i][], op[i].h);
}// 这里判断是不是可以直接跳到地面上。
//cout << dp[i][0] << " " << dp[i][1] << endl;
}
int cc = min(dp[n + ][], dp[n + ][]);
cout << cc << endl;
}
return ;
}

6、poj 2533 Longest Ordered Subsequence

  题意:给出一个数字序列,求最长递增子序列的长度。

  思路:模板题。

 #include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = ;
int num[maxn];
int pre[maxn];
int dp[maxn];
int n;
int DPn2()
{
memset(pre, -, sizeof(pre));
dp[] = ;
int ans = ;
for (int i = ; i < n; i++)
{
dp[i] = ;
for (int j = i - ; j >= ; j--)
{
if (num[i] > num[j] && dp[j] + > dp[i])
{
dp[i] = dp[j] + ;
pre[i] = j;
}
}
if (dp[i] > ans) ans = dp[i];
}
return ans;
}
int Vnlogn()
{
vector<int>v;
for (int i = ; i < n; i++)
{
if (v.empty()) v.push_back(num[i]);
else if (num[i] > v.back()) v.push_back(num[i]);
else
{
int pos = lower_bound(v.begin(), v.end(), num[i]) - v.begin();
v[pos] = num[i];
}
}
return v.size();
}
int main()
{
while (~scanf("%d", &n))
{
for (int i = ; i < n; i++) scanf("%d", &num[i]);
printf("%d\n", DPn2());
//printf("%d\n", Vnlogn());
}
return ;
}

7、poj 3186 Treats for the Cows

  题意:有n个物品,每次可以从首或者尾选择商品卖出,卖出的价格为商品的价值*年份(初始时每个商品年份都为1,每卖出一个商品后剩下商品的年份+1)。问最后最大的收益值。

  思路:dp[i][j]表示卖完第i到第j的最大收益。则dp[j][j + l - 1] = max(dp[j + 1][j + l - 1] + num[j] * (n - l + 1), dp[j][j + l - 2] + num[j+l-1] * (n - l + 1));l为当前枚举的区间长度,n-l+1表示其是第n-l+1个卖出。

 #include<iostream>
#include<memory.h>
#include<algorithm>
using namespace std;
const int maxn = ;
int num[maxn];
int dp[maxn][maxn];//[i][j]表示从第i到第j最大的收益。
int main()
{
int n;
while (~scanf("%d", &n))
{
memset(dp, , sizeof(dp));
for (int i = ; i <= n; i++)
{
scanf("%d", &num[i]);
dp[i][i] =num[i]* n;
}
for (int l=;l<=n;l++)
{
for (int j = ; j+l- <= n; j++)
{
dp[j][j + l - ] = max(dp[j + ][j + l - ] + num[j] * (n - l + ), dp[j][j + l - ] + num[j+l-] * (n - l + ));
}
}
printf("%d\n", dp[][n]);
}
return ;
}

8、hdu 2859 Phalanx

  题意:给出n*n的矩阵,求最大对称子矩阵。

  思路:dp[i][j]表示左下角为(i,j)的对称矩阵的维数。可以从dp[i-1][j+1]转换。

 #include<iostream>
#include<algorithm>
using namespace std;
int n;
const int maxn = ;
char mp[maxn][maxn];
int dp[maxn][maxn];//dp[i][j]表示左下角为(i,j)的对称矩阵的维数。可以从dp[i-1][j+1]转换
int main()
{
while (~scanf("%d", &n))
{
if (n == )break;
for (int i = ; i <= n; i++)
{
for (int j = ; j <= n; j++) cin >> mp[i][j];
}
int ans = ;
for (int i = ; i <= n; i++)
{
for (int j = n; j >= ; --j)
{
dp[i][j] = ;
if (i == || j == n) continue;
int ll = dp[i - ][j + ];
for (int k = ; k <= ll; k++)
{
if (mp[i - k][j] == mp[i][j + k]) dp[i][j]++;
else break;
}
ans = max(ans, dp[i][j]);
}
}
printf("%d\n", ans);
}
return ;
}

9、poj 3616 Milking Time

  题意:共有n个小时,给出一些划分时间区间及区间内挤奶的效率,每次挤完奶后员工必须休息R小时,问如何安排,使得最后总的效率最大。

  思路:DP[i]表示到时刻i为止的最大效率。哎,好不容易一次不看题解自己推出dp过程,加油233

 #include<iostream>
#include<algorithm>
#include<memory.h>
using namespace std;
int n, m, r;
struct node
{
int st;
int ed;
int f;
}pds[];
int dp[];
bool Cmp(const node&a, const node&b)
{
if (a.st == b.st)return a.ed < b.ed;
else return a.st < b.st;
}
int main()
{
while (~scanf("%d%d%d", &n, &m, &r))
{
for (int i = ; i <= m; i++)
{
scanf("%d%d%d", &pds[i].st, &pds[i].ed, &pds[i].f);
} sort(pds+, pds + m+, Cmp);
pds[].st = , pds[].ed = , pds[].f = ;
memset(dp, , sizeof(dp));
int ans = ;
for (int i = ; i <= m; i++)
{
int ed = pds[i].ed + r;
int ee = pds[i].st;
if (ed > n + r)continue;
for (int j = ; j < i; j++)
{
int te;
if (j == ) te = pds[j].ed;
else te = pds[j].ed + r;
if (te <= ee)
{
dp[ed] = max(dp[ed], dp[te] + pds[i].f);
ans = max(dp[ed], ans);
}
}
}
printf("%d\n", ans);
}
return ;
}

10、hdu 2955 Robberies

  题意:给出最大被抓概率maxp和银行数目,以及每个银行的能偷的钱财以及被抓的概率,求最大能偷到的钱数。

  思路:dp[i]表示偷当前钱数的最大不被抓的概率,那么取不被抓概率大于1-maxp的最大i即为答案。

 #include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int val[];
double w[];
double dp[];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
double maxw;//被抓的概率
int n;
int sum = ;
scanf("%lf%d", &maxw, &n);
for (int i = ; i < n; i++) scanf("%d%lf", val + i, w + i),sum+=val[i];
int maxans = ;
memset(dp, , sizeof(dp));
dp[] = ;
for (int i = ; i < n; i++)
{
for (int v = sum; v >= val[i]; v--)
{
dp[v] = max(dp[v], dp[v - val[i]] *(-w[i]));//当前偷价值为v时不被抓的概率
if (dp[v] > - maxw) maxans = max(maxans, v);
}
}
printf("%d\n", maxans);
}
return ;
}

11、poj 2923 Relocation

  题意:有两辆卡车,有各自的最大载重c1,c2,有n件家具,现在需要把这些家具从一个地方搬到另一个地方,问最少的搬运次数。

  思路:先状态压缩,确定所有可行的状态(所选择的货物能够在一趟内被搬运),然后对所有可行状态进行01背包(注意,转移的条件要求两种相应的状态不能有交集<即每种货物最多只会被搬运一次>),得到解。

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxst = << ;
const int INF = 0x3f3f3f3f;
const int maxn = ;
const int maxw = ;
int st[maxst];//储存可行状态
int dp[maxst];
bool vis[maxw];
int w[maxn];
int n, c1, c2;
bool ok(int cst)
{
memset(vis, , sizeof(vis));
vis[] = true;
int sum = ;
for (int i = ; i < n; i++)
{
if ((cst >> i)&)
{//如果要运走当前货物
sum += w[i];
for (int j = c1; j >= w[i]; j--)
{
if (vis[j - w[i]]) vis[j] = true;
}
}
}
//if (cst == (1 << n) - 1) printf("%d\n", sum);
if (sum > c1 + c2) return false;
for (int i = ; i <= c1; i++)
{
if (vis[i] && sum - i <= c2) return true;
}
return false;
}
int main()
{
int t;
scanf("%d", &t);
int Case = ;
while (t--)
{
scanf("%d%d%d", &n, &c1, &c2);
for (int i = ; i < n; i++) scanf("%d", w + i); int tot = ;
int maxtot = ( << n) - ;
for (int i = ; i <= maxtot; i++)
{
dp[i] = INF;
if (ok(i)) st[tot++] = i;
}
//对状态进行0/1背包
dp[] = ;
for (int i = ; i < tot; i++)
{
for (int j = maxtot; j >= ; j--)
{
if (dp[j] == INF) continue;
if ((j&st[i]) == )
{
//if ((j | st[i]) == maxtot) printf("%d %d\n%d %d\n", j, st[i], dp[j], dp[st[i]]);
dp[j | st[i]] = min(dp[j | st[i]], dp[j] + );
}
}
}
printf("Scenario #%d:\n%d\n", Case++, dp[maxtot]);//题目保证每个家具都能被运走,不存在dp[maxtot]=INF的情况
if (t) printf("\n");
}
return ;
}

12、hdu 3466 Proud Merchants

  题意:每个商人有一个货物,当你的钱不少于Qi时商人才会和你交易。问用M的钱,求买到的货物的最大价值和。

  思路:如果要先买A货物,再买B货物,那么首先需要保证Pa+Qb>Pb+Qa,即Qa-Pa<Qb-Pb,这样才能保证dp不会受到影响。

 #include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = ;
const int maxv = ;
struct node
{
int p, q, v;
friend bool operator<(const node &a, const node &b)
{
return a.q-a.p < b.q-b.p;
}
}item[maxn];
int dp[maxv];
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m))
{
for (int i = ; i < n; i++) scanf("%d%d%d",&item[i].p,&item[i].q,&item[i].v);
sort(item, item + n);
memset(dp, , sizeof(dp));
for (int i = ; i < n; i++)
{
for (int j = m; j >= max(item[i].p,item[i].q); j--)
{
dp[j] = max(dp[j], dp[j - item[i].p] + item[i].v);
}
}
printf("%d\n", dp[m]);
}
return ;
}

13、hdu 2639 Bone Collector II

  题意:求01背包第k大值

  思路:每个状态保存前k个值,用到多路归并的思想。

 #include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int val[];
int vol[];
int dp[][];
int pre[];
int trans[];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, v, k;
scanf("%d%d%d", &n, &v, &k);
for (int i = ; i < n; i++) scanf("%d", val+i);
for (int i = ; i < n; i++) scanf("%d", vol+i);
memset(dp, , sizeof(dp));
memset(pre, , sizeof(pre));
memset(trans, , sizeof(trans));
for (int i = ; i < n; i++)
{
for (int tv = v; tv >= vol[i]; tv--)
{
for (int j = ; j < k; j++)
{
pre[j] = dp[tv][j];
trans[j] = dp[tv - vol[i]][j]+val[i];
}
int id1 = , id2 = , cur = ;
while (cur < k && (id1 < k || id2 < k))
{
if (pre[id1] >= trans[id2]) dp[tv][cur] = pre[id1++];
else dp[tv][cur] = trans[id2++];
if (cur == )cur++;
else if (dp[tv][cur] != dp[tv][cur - ]) cur++;
}
}
}
printf("%d\n", dp[v][k - ]);
}
return ;
}

14、poj 2184 Cow Exhibition

  题意:每头牛都有funny值fi和smart值si(有正负),现在需要选出一些牛,使得所有牛的funny值之和TF与smart值之和TS不小于0,同时TS+TF最大。

  思路:因为有负值,所以向右偏移;然后求每个对应的TF下的最大TS。如果s[i]大于0,则dp[v]从dp[v-s[i]]转移过来。因为当前容量为正,则相当于从v-s[i]加上s[i],然后加上价值f[i];如果s[i]小于0,则dp[v]从dp[v-s[i]]即dp[v+|s[i]|]转移过来。因为当前容量为负,则相当于从v+|s[i]|减去|s[i]|,然后加上价值f[i].

 //基本思路:找到当前ts下最大的tf.之后找最大的ts+tf

 #include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int s[];
int f[];
const int maxv = ;
const int INF = 0x3f3f3f3f;
int dp[maxv];
int main()
{
int n;
while (~scanf("%d", &n))
{
for (int i = ; i < n; i++)
{
scanf("%d%d", s + i, f + i);
}
int sumv =n*;
memset(dp, -INF, sizeof(dp));
int SHIFT = n*;
dp[SHIFT] = ;
for (int i = ; i < n; i++)
{
if (s[i] >= )
{/*如果s[i]大于0,则dp[v]从dp[v-s[i]]转移过来。因为当前容量为正,则相当于从v-s[i]加上
s[i],然后加上价值f[i]*/
for (int v = sumv; v >= s[i]; v--) dp[v] = max(dp[v], dp[v - s[i]] + f[i]);
}
else
{/*如果s[i]小于0,则dp[v]从dp[v-s[i]]即dp[v+|s[i]|]转移过来。因为当前容量为负,则相当于从v+|s[i]|减去
|s[i]|,然后加上价值f[i]*/
for (int v = ; v <= sumv + s[i]; v++) dp[v] = max(dp[v], dp[v - s[i]] + f[i]);
}
}
int ans = ;
for (int i = SHIFT; i <= sumv; i++)
{
if(dp[i]>=)ans = max(ans, dp[i] + i - SHIFT);
}
printf("%d\n", ans);
}
return ;
}

15、uva 562 Dividing coins

  题意:需要把所有硬币分成两堆,使得两堆价值差最小。

  思路:设置容量为所有硬币的总价值/2,然后dp.

 #include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = ;
const int maxw = ;
int dp[maxw];
int w[maxn];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
int sum = ;
for (int i = ; i < n; i++)
{
scanf("%d", &w[i]);
sum += w[i];
}
int cmax = sum / ;
memset(dp, , sizeof(dp));
for (int i = ; i < n; i++)
{
for (int cw = cmax; cw >= w[i]; cw--)
{
dp[cw] = max(dp[cw], dp[cw - w[i]] + w[i]);
}
}
printf("%d\n", sum - * dp[cmax]);
}
return ;
}

16、uva 624 CD

  题意:需要把一些CD刻录在磁带上,问最多能够刻录的时长是多少?

  思路:简单01背包,注意记录。

 #include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
using namespace std;
const int maxn = ;
int Time[];
int vis[][maxn];
int dp[maxn];
int main()
{
int n, num;
while (~scanf("%d", &n))
{
scanf("%d", &num);
for (int i = ; i <= num; i++)
{
scanf("%d", &Time[i]);
}
memset(dp, , sizeof(dp));
memset(vis, -,sizeof(vis));
for (int i = ; i <= num; i++)
{
for (int j = n; j >= Time[i]; j--)
{
if (dp[j - Time[i]] + Time[i] > dp[j])
{
dp[j] = dp[j - Time[i]] + Time[i];
vis[i][j] = i;
}
}
}
vector<int>Order;
int w = n;
for (int i = num; i >= ; --i)
{
if (vis[i][w] != -)
{
Order.push_back(Time[vis[i][w]]);
w -= Time[vis[i][w]];
}
}
int sz = Order.size();
for (int i = sz - ; i >= ; i--) printf("%d ", Order[i]);
printf("sum:%d\n", dp[n]);
}
return ;
}

17、hdu 2546 饭卡

  题意:当卡上余额大于等于5元时,一定可以购买成功一样菜(无论该菜的价格是否大于5元)。求最小的余额数

  思路:先用当前拥有的额度-5元去买除最贵菜之外的菜,再用剩下的钱去买那个最贵的菜。

 #include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = ;
const int maxm = ;
int price[maxn];
int dp[maxm];
int main()
{
int n;
while (~scanf("%d", &n) && n)
{
for (int i = ; i <= n; i++) scanf("%d", &price[i]);
int inim;
scanf("%d", &inim);
if (inim < )
{
printf("%d\n", inim);
continue;
}
inim -= ;//保留5元,用5元去买最贵的菜
sort(price + , price + + n);
memset(dp, , sizeof(dp));//dp[i]表示用i块钱能够买的菜总花费最高
for (int i = ; i <=n-; i++)
{
for (int j = inim; j >= price[i]; --j)
{
dp[j] = max(dp[j], dp[j - price[i]] + price[i]);
}
}
printf("%d\n",inim+-dp[inim]-price[n]);
}
return ;
}

18、poj 3624 Charm Bracelet

  题意:需要串手链,使得总重不超过M的情况下Di之和最大

  思路:01背包

 #include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = ;
const int maxw = ;
int rat[maxn];
int wt[maxn];
int dp[maxw];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) scanf("%d%d", &wt[i], &rat[i]);
for (int i = ; i <= n; i++)
{
for (int v = m; v >= wt[i]; v--)
{
dp[v] = max(dp[v], dp[v - wt[i]] + rat[i]);
}
}
printf("%d\n", dp[m]);
return ;
}

19、hdu 2602 Bone Collector

  题意:需要收集骨头,在不超过背包容量的情况下求最大价值。

  思路:01背包

 #include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = ;
const int maxv = ;
int vali[maxn];
int voli[maxn];
int dp[maxv];
int main()
{
int t;
int n, mv;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &mv);
for (int i = ; i <= n; i++) scanf("%d", &vali[i]);
for (int i = ; i <= n; i++) scanf("%d", &voli[i]);
memset(dp, , sizeof(dp));
for (int i = ; i <= n; i++)
{
for (int j = mv; j >= voli[i]; j--)
{
dp[j] = max(dp[j], dp[j - voli[i]] + vali[i]);
}
}
printf("%d\n",dp[mv]);
}
return ;
}

DP专题·二的更多相关文章

  1. 「kuangbin带你飞」专题二十 斜率DP

    layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...

  2. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  3. 决策单调性优化dp 专题练习

    决策单调性优化dp 专题练习 优化方法总结 一.斜率优化 对于形如 \(dp[i]=dp[j]+(i-j)*(i-j)\)类型的转移方程,维护一个上凸包或者下凸包,找到切点快速求解 技法: 1.单调队 ...

  4. 区间dp专题练习

    区间dp专题练习 题意 1.Equal Sum Partitions ? 这嘛东西,\(n^2\)自己写去 \[\ \] \[\ \] 2.You Are the One 感觉自己智力被吊打 \(dp ...

  5. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  6. UI标签库专题二:JEECG智能开发平台Column(列) 子标签

    UI标签库专题二:JEECG智能开发平台Column(列) 子标签  1.1. Column(列) 子标签 1.1.1. 演示样例 <t:dgCol title="年龄" ...

  7. 开发指南专题二:JEECG微云高速开发平台JEECG框架初探

    开发指南专题二:JEECG微云高速开发平台JEECG框架初探 2.JEECG框架初探 2.1演示系统 打开浏览器输入JEECG演示环境界址:http://demo.jeecg.org:8090/能够看 ...

  8. 状压dp专题复习

    状压dp专题复习 (有些题过于水,我直接跳了) 技巧总结 : 1.矩阵状压上一行的选择情况 \(n * 2^n\) D [BZOJ2734][HNOI2012]集合选数 蒻得不行的我觉得这是一道比较难 ...

  9. 树形dp专题总结

    树形dp专题总结 大力dp的练习与晋升 原题均可以在网址上找到 技巧总结 1.换根大法 2.状态定义应只考虑考虑影响的关系 3.数据结构与dp的合理结合(T11) 4.抽直径解决求最长链的许多类问题( ...

随机推荐

  1. FlashBuilder 4.6序列号破解

    1424-4827-8874-7387-0243-7331 1424-4938-3077-5736-3940-5640 具体步骤如下: 1.到Adobe官网下载FlashBuilder 4.6,有简体 ...

  2. php调用C代码的实现方法

    在php程序中需要用到C代码,应该是下面两种情况: 1 已有C代码,在php程序中想直接用2 由于php的性能问题,需要用C来实现部分功能 针对第一种情况,最合适的方法是用system调用,把现有C代 ...

  3. Paxos发展、算法原理

    Paxos 发展史 Leslie Lamport所提出的Paxos算法是现代分布式系统中的一项重要的基础性技术,得到广泛的应用. Paxos的整个发展过程大概可以分为三个阶段: 第一阶段:萌芽期,大致 ...

  4. Istio官方文档中文版

    Istio官方文档中文版 http://istio.doczh.cn/ https://istio.io/docs/concepts/what-is-istio/goals.html 为什么要使用Is ...

  5. jquery datagrid设置pageSize不起作用

    http://www.2cto.com/kf/201212/178098.html —————————————————————————————————————————————————————————— ...

  6. Oracle安装完成后,如何用命令行启动和关闭数据库?

    Oracle安装完成后,如何用命令行启动和关闭数据库? 解答: 打开:STARTUP [FORCE] [RESTRICT] [PFILE= filename] [OPEN [RECOVER][ dat ...

  7. TCP/IP协议族-----15、传输控制协议(TCP)

  8. socket.io 中文api

    1. 服务端 io.on('connection',function(socket)); 监听客户端连接,回调函数会传递本次连接的socket io.sockets.emit('String',dat ...

  9. 面试题思考:什么是基于注解的切面实现?(AOP是Aspect Oriented Program的首字母缩写)

    首先解释下AOP :在程序运行时,动态的将代码切入到类的指定方法.指定位置上的编程思想就是面向切面编程 一般而言,我们管切入到指定类指定方法的代码片段为切面,而切入的哪些类.哪些方法则叫切入点.有了A ...

  10. shop++源码反编译----随笔

    一.applicationContext-mvc.xml配置 1.读取配置文件 <context:property-placeholder location="classpath*:/ ...