1、UVALive 3971 Assemble 组装电脑
分析:最小值最大问题,一般采用二分来解决。。。本题核心:品质因子尽量大
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iostream>
using namespace std;
int cnt;
map<string, int> id;
int ID(char* s){
if (!id.count(s)) id[s] = cnt++;
return id[s];
} //添加编号
struct Component
{
int price;
int quality;
};
const int maxn = 1005;
int n, b;
vector<Component> comp[maxn];
//检测当前品质是否符合
bool ok(int q){
int sum = 0;
for (int i = 0; i<cnt; i++)
{
int cheapest = b+1, m = comp[i].size();
for (int j = 0; j<m; j++)
if (comp[i][j].quality >= q) cheapest = min(cheapest, comp[i][j].price); //找每种类型的最便宜且满足品质的物品
if (cheapest == b+1) return false;
sum += cheapest;
if (sum > b ) return false;
}
return true;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &b);
cnt = 0;
for (int i = 0; i<n; i++){
comp[i].clear();
}
id.clear();
int maxa = 0;
for (int i = 0; i<n; i++)
{
char type[25], name[25];
int quality, price;
scanf("%s%s%d%d", type, name, &price, &quality);
comp[ID(type)].push_back((Component){price, quality});
maxa = max(maxa, quality);
}
int L = 0, R = maxa;
while (L<R) //二分查找
{
int M = L + (R-L+1)/2;
if (ok(M)) L = M;
else R = M-1;
}
printf("%d\n", L);
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
const double PI = acos(-1.0); // PI
const int maxn = 10005;
double A[maxn];
int n, f;
bool ok(double area)
{
int sum = 0;
for (int i = 0; i<n; i++)
sum += floor(A[i] / area); // 每个圆形派可以切成 [PI*r*r]/x 个派
return sum >= f+1; // 判断是否存在矛盾
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d %d", &n, &f);
double maxa = 0;
for (int i = 0; i<n; i++)
{
int r;
scanf("%d", &r);
A[i] = PI*r*r;
if (maxa < A[i]) {
maxa = A[i];
}
}
double L = 0, R = maxa;
while (R-L > 1e-5) //double 类型判断是否相等
{
double M = (L+R)/2;
if (ok(M)) L = M;
else R = M;
}
printf("%.4lf\n", L);
}
return 0;
}
3、UVALive 3177 Beijing Guard 长城守卫
分析:当n为偶数, 答案肯定是相邻两个人的r值之和的最大值,即 p = max{r[i] + r[i+1]};
当n为奇数, 这时候需要二分答案 ,假设第一个人的礼物为 1 ~ r1,那么最优的分配策略应该如此:编号为偶数的尽量靠前取,编号为奇数的尽量往后取,最后判定编号为1 和编号为n所取礼物是否冲突即可。
所以只需记载每个人在 1~r[1]取了几个,在r[1]+1~r[n]取了几个便可(本题分别用le[], ri[]表示)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int n, r[maxn], le[maxn], ri[maxn];
bool ok(int p)
{
int x = r[1], y = p - r[1];
le[1] = x;
ri[1] = 0;
for (int i = 2; i<=n; i++)
{
if (i%2 == 1) //尽量往后取
{
ri[i] = min(y - ri[i-1], r[i]);
le[i] = r[i] - ri[i];
}
else //尽量往前取
{
le[i] = min(x - le[i-1], r[i]);
ri[i] = r[i] - le[i];
}
}
return le[n] == 0; //判断1和n是否产生冲突
}
int main()
{
while (scanf("%d", &n) && n)
{
for (int i = 1; i<=n; i++) scanf("%d", &r[i]);
if (n == 1) { //特判 n == 1
printf("%d\n", r[1]);
continue;
}
r[n+1] = r[1];
int L = 0, R = 0;
for (int i = 1; i<=n; i++) L = max(L, r[i]+r[i+1]);//偶数时的至少礼物数
if (n%2 == 1)
{
for (int i = 1; i<=n; i++) R = max(R, r[i]*3);//构造最大情况
while (L<R)
{
int M = (R-L)/2 + L;
if (ok(M)) R = M;
else L = M+1;
}
}
printf("%d\n", L);
}
return 0;
}