Mem478

这次在DIV1挂蛋了。

250的题大意是这样的,给一个1<=x<1000000007,对x只能执行两种操作4x+3或者8x+7,问说最少能用几步到达1000000007 * a(a属于自然数),最多只能扩展到100000步,否则输出-1,刚开始以为BFS的话,状态数会太多,就找其中的规律,可惜不够敏感4x+3,8x+7都是2^n*x+2^n-1的这种形式,对于这种形式的两种操作是可以等价于一种操作的,如果可以等价于一种操作的话,那状态数就没有之前想象的那样多了,直接BFS,用map来记状态就可以了。2^n*x+2^n-1经过2^m*x+2^m-1运算后,就变成了2^(m+n)*x+2^(m+n)-1,所以这两种操作,其实就等价于一种操作了,BFS就可以做这题了。其实问题可以退化成这样,起点为0,你可以向前2步或3步,给定终点X,问说,从起点到终点,最少几步可以到达。从方程上看2x+3y=z(z为整数)是有(x,y)整数对的解的,因为gcd(2,3)整除z,但这里需要x,y是非负整数,因此当z是1时,是无解的。构造最小的x+y的办法,就用贪心的想法,尽量走3步的,到最后走2步的,这样走的步数最少。

500的题大意是这样,有n(n<=15)个瓶子(容量C<=45),装了一些水,水的体积是离散的,为整数,每个对应的离散值有相应的价格,现在容许对任意A,B两个瓶子执行无数次这样的操作,从A倒向B,或是从B倒向A,直到一边空,或者满,问说最后所能得到的最优的价格。这道是个最优化问题,想到15这个数字是二进制的暗示,可以搞定所有状态后取最优值,但没和DP联系在一起,没想出来。应该是这样的,对于mask当前的状态,任意从中选出m个瓶子,做倒水的操作,剩下的用于状态扩展,对于这些倒水的瓶子,全参与倒水,如果不全参与倒水,则这样的情况在枚举其他子集的时候就已经出现了。然后从中取最优值就可以了。

 

代码
/*
Mem478
DIV1 500pt
*/
#include
<iostream>
#include
<vector>
using namespace std;

vector
<int> b;
vector
<int> p;
int c, n;
int dp[1 << 16];

int go(int mask)
{
if(dp[mask] != -1) return dp[mask];
int cost = 0;
for(int ma = mask; ma; ma = (ma - 1) & mask)
{
int cnt = 0, sum = 0;
for(int i = 0; i < n; i++)
{
if(ma & (1 << i))
{
cnt
++;
sum
+= b[i];
}
}
int t = (sum / c) * p[c] + p[sum % c] + (cnt - sum / c - 1) * p[0] + go(mask ^ ma);
cost
= max(t, cost);
}
dp[mask]
= cost;
return cost;
}

class KiwiJuice
{
public:
int theProfit(int C, vector <int> bottles, vector <int> prices)
{
b
= bottles;
p
= prices;
c
= C;
n
= b.size();
memset(dp,
-1, sizeof(dp));
return go((1 << n) - 1);
}
};

 

 

 

posted @ 2010-08-06 11:30  litstrong  阅读(168)  评论(0编辑  收藏  举报