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;
}