问题 F: 维斯顿的烦劳
描述
维斯顿经营着一个盗版贩卖的商店(偶尔也会适应国家政策,摆地摊来扩大销售)。当然大家都愿意支持正版,可惜盗版生意依旧火爆,每次上货基本就是被一抢而空。为此维斯顿不断的扩大自己的商店,力求可以放下更多的商品,可惜现在手上的资金有限没法扩容商店,为了最快速的获得资金,那他就需要选择那些利润大的商品进行贩卖。我们假设商店可以放下V体积的物品。维斯顿在上货的时候有K件物品可以选择,每件物品有体积(S),和利润(P)两个特征。要在K件物品中选择一些物品体积总和不超过V。使得利润之和最大。格式
输入格式
输入一个浮点数 V(V<=1000,modf(V)>=0.01),和一个整数 K(k<=100)
接着是K行,包含两个浮点数S,P,(S<=V,P<=100,modf(S)>=0.01)输出格式
输出一个浮点数表示可以得到最大利润之和。样例
样例输入 Copy10 3
5 4
3 3
5 4样例输出 Copy
8.000000
典型的背包问题,可是还是错了好多。因为V是浮点数,所以不能用来当作下标,这样一来就不能用记忆化数组,当时我就想用set来索引,可是错误百出,因为对set不熟悉,下面是错误的代码:
#include <bits/stdc++.h>
using namespace std;
struct node
{
float v = 0, p = 0;
};
node a[110];
float v;
int k;
float max(float a, float b)
{
return a > b ? a : b;
}
struct ans
{
int i;
float v;
float ansr;
bool operator<(const ans &a) const
{
if (this->i == a.i && this->v == a.v)
return false;
else
return true;
}
};
set<ans> mem;
float solove(int i, float v)
{
ans t = {i, v};
if (mem.count(t))
return mem.find(t)->ansr;
if (i == k)
return 0;
t.i = i, t.v = v;
if (v < a[i].v)
t.ansr = solove(i + 1, v);
else
t.ansr = max(solove(i + 1, v), solove(i + 1, v - a[i].v) + a[i].p);
mem.insert(t);
return t.ansr;
}
int main(void)
{
cin >> v >> k;
for (int i = 0; i < k; i++)
cin >> a[i].v >> a[i].p;
printf("%lf", solove(0, v));
//cout<<solove(0,v);
return 0;
}
后来仔细看题,发现一个东西:modf(V)>=0.01
!!!我可以把V*100,这样不就可以转换成整数了嘛,最后ans/100不就行了,早看到这个也不会让我瞎琢磨那么久了(仔细审题很重要)。
下面是AC代码:
#include <bits/stdc++.h>
using namespace std;
double max(double a, double b)
{
return a > b ? a : b;
}
struct obj
{
int s;
double p;
};
int main(void)
{
double t;
int v, k;
obj a[110];
double dp[110000] = {0};
cin >> t >> k;
v = t * 100;
for (int i = 1; i <= k; i++)
{
cin >> t >> a[i].p;
a[i].s = t * 100;
}
for (int i = 1; i <= k; i++)
for (int j = v; j > 0; j--)
if (j >= a[i].s)
dp[j] = max(dp[j], dp[j - a[i].s] + a[i].p);
printf("%lf\n", dp[v]);
return 0;
}
问题 A: 切绳子
描述
有n条绳子,长度分别为L[i]。如果从他们中切割出k条长度相同的绳子的话,这k条绳子每条最长能有多长?(答案保留小数点后两位(直接舍掉两位后的小数),规定1单位长度的绳子最多可以切割成100份)格式
输入格式
包含多组输入
输入n,k,(1<=n,k<=10000)
然后n行,输入L[i],代表每一条绳子的长度(1<=L[i]<=100000)输出格式
切出k条长度相等的绳子最大长度是多少,输出保留两位小数样例
样例输入 Copy
4 11
8.02
7.43
4.57
5.39
样例输出 Copy
2.00
这题其实简单,但是犯了一个非常粗心的错误,没有把double转换成int,所以结果有问题:
bool check(double ans)
{
int count = 0;
for (int i = 0; i < n; i++)
count += (int)L[i] / ans;
if (count >= k)
return true;
return false;
}
改完之后:
bool check(double ans)
{
int count = 0;
for (int i = 0; i < n; i++)
count += (int)L[i] /(int)ans;
if (count >= k)
return true;
return false;
}
AC代码:
#include <bits/stdc++.h>
#define INF ((unsigned(-1)) >> 1)
using namespace std;
const int maxn = 10010;
int n, k;
double L[maxn];
bool check(double ans)
{
int count = 0;
for (int i = 0; i < n; i++)
count += (int)L[i] / (int)ans;
if (count >= k)
return true;
return false;
}
int main(void)
{
while (cin >> n >> k)
{
double l = 0, r = INF, mid = (l + r) / 2, ans = 0;
for (int i = 0; i < n; i++)
{
cin >> L[i];
L[i] *= 100;
}
while (l <= r)
{
if (check(mid))
{
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
mid = (l + r) / 2;
}
printf("%.2lf\n", ans / 100);
}
return 0;
}
问题 B: 如何放牛
描述
农夫有n个牛栏,m头牛,然后要让你把m个牛都放进牛栏里,让两头牛之前的最大的最小距离格式
输入格式
多组输入
输入n,m (1<=m<=n<=100000)
下面n行是牛栏的位置xi (0 <= xi <=1,000,000,000)输出格式
输出两头牛最大的最小距离样例
样例输入 Copy
5 3
1
2
8
4
9
样例输出 Copy
3提示
FJ可以将他的3头奶牛放在位置1,4和8的摊位上,最小距离为3.大量输入数据,建议使用scanf。
就如题目提示一样,我用cin超时了。还有就是,check函数想当然的去写,结果错了,后来排查半天才出来。哎,菜是原罪。
这是错误的check:
bool check(int mid)
{
int count = 0;
int begin = 0, end = 1;
while (end < n)
{
while (end < n && x[end] - x[begin] < mid)
end++;
if (x[end] - x[begin] >= mid)
count++;
else
return false;
begin = end, end = end + 1;
}
if (count >= m)
return true;
return false;
}
我以为 if (x[end] - x[begin] >= mid)
满足的话,说明end已经大于等于n了,可是没考虑到end等于n的时候,越界后x[end]的结果未知,所以if的成立也未知,然后就WA了。
改之后的代码:
bool check(int mid)
{
int count = 1;
int begin = 0, end = 1;
while (end < n)
{
while (end < n && x[end] - x[begin] < mid)
end++;
if (end < n && x[end] - x[begin] >= mid)
count++;
begin = end, end = end + 1;
}
if (count >= m)
return true;
return false;
}
AC代码:
#include <bits/stdc++.h>
typedef unsigned long long ull;
#define INF ((unsigned(-1)) >> 1)
const int maxn = 100100;
ull x[maxn];
int n, m;
using namespace std;
bool check(int mid)
{
int count = 1;
int begin = 0, end = 1;
while (end < n)
{
while (end < n && x[end] - x[begin] < mid)
end++;
if (end < n && x[end] - x[begin] >= mid)
count++;
begin = end, end = end + 1;
}
if (count >= m)
return true;
return false;
}
int main(void)
{
while (cin >> n >> m)
{
for (int i = 0; i < n; i++)
scanf("%llu", x + i);
sort(x, x + n);
int l = 0, r = INF, mid = (l + r) / 2, ans = 0;
while (l <= r)
{
if (check(mid))
{
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
mid = (l + r) / 2;
}
cout << ans << endl;
}
return 0;
}