1. 程式人生 > >2017暑假訓練之二分法

2017暑假訓練之二分法

二分法判斷解是否可行
POJ 1064 Cable master
double a[maxn];
int n, k;

bool check(double mid) {
	int cnt = 0;
	for (int i = 0; i < n; ++i) cnt += a[i] / mid;
	return cnt >= k;
}

int main() {
	while (scanf("%d%d", &n, &k) == 2) {
		for (int i = 0; i < n; ++i) scanf("%lf", &a[i]);
		double l = 0, r = INF;
		for (int i = 0; i < 100; ++i) {
			double mid = (l + r) / 2;
			if (check(mid)) l = mid;
			else r = mid;
		}
		//注意不能四捨五入
		printf("%.2lf\n", floor(l * 100) / 100);
	}
	return 0;
}
最大化最小值
POJ 2456 Aggressive cows
11110000取1
int x[maxn];
int n, c;

bool check(int mid) {
	int cur = x[0], i = 0, cnt = 1;
	while (1) {
		while (i < n && x[i] - cur < mid) ++i;
		if (i == n) break;
		cur = x[i++];//每次從選取的下一個開始選擇
		++cnt;
	}
	return cnt >= c;
}

int main() {
	while (~scanf("%d%d", &n, &c)) {
		for (int i = 0; i < n; ++i) scanf("%d", &x[i]);
		sort(x, x + n);
		int l = 0, r = INF;
		while (r - l > 1) {
			int mid = (l + r) >> 1;
			if (check(mid)) l = mid;
			else r = mid;
		}
		printf("%d\n", l);
	}
	return 0;
}
POJ 3258 River Hopscotch
寫掛了無數次check。。。真讓人頭大啊。。
要得到sum > mid, 應該在while內賦值,而要使sum恰好小於,則判斷條件為sum+val > mid。
int n, L, m, d[maxn], a[maxn];

bool check(int mid) {
	int i = 1, sum = d[0], cnt = 0;//保持sum與i差1
	while (1) {
		while (i <= n && sum < mid) {
			sum += d[i++], cnt++;
		}
		if (sum < mid) return false;
		if (i > n) break;
		sum = d[i++];
	}
	return cnt <= m;
}

int main() {
	while (~scanf("%d%d%d", &L, &n, &m)) {
		for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
		a[0] = 0, a[n+1] = L;
		sort(a, a + n + 2);
		int mind = INF;
		for (int i = 0; i <= n; ++i) {
			d[i] = a[i+1] - a[i];
			mind = min(d[i], mind);
		}
		int l = mind, r = L+1;
		while (r - l > 1) {
			int mid = (l + r) >> 1;
			if (check(mid)) l = mid;
			else r = mid;
		}
		printf("%d\n", l);
	}
	return 0;
}
最大化平均值
POJ 2976 Dropping tests
int a[maxn], b[maxn], n, k;
double sum[maxn];

bool check(double mid) {
	for (int i = 0; i < n; ++i) sum[i] = (LL)100 * a[i] - b[i] * mid;
	sort(sum, sum + n);
	double ret = 0;
	for (int i = n - 1; i >= k; --i) ret += sum[i];
	return ret >= EPS;
}

int main() {
	while (scanf("%d%d", &n, &k)) {
		if (!n && !k) break;
		for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
		for (int i = 0; i < n; ++i) scanf("%d", &b[i]);
		double l = 0, r = INF;
		for (int i = 0; i < 100; ++i) {
			double mid = (l + r) / 2;
			if (check(mid)) l = mid;
			else r = mid;
		}
		printf("%.0lf\n", l);
	}
	return 0;
}
查詢第k大的值
POJ 3579 Median
000011111取1
int n, m, a[maxn];

bool check(int mid) {
	int cnt = 0;
	int val;
	for (int i = 0; i < n; ++i) {
		val = mid + a[i];
		if (val > a[n - 1]) break;
		cnt += n + (a - upper_bound(a, a + n, val));
	}
	return cnt <= m;
}

int main() {
	while (~scanf("%d", &n)) {
		for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
		m = (n*(n - 1))>>2;
		sort(a, a + n);
		int l = 0, r = INF;
		while (r - l > 1) {
			int mid = (l + r) >> 1;
			if (check(mid)) r = mid;
			else l = mid;
		}
		printf("%d\n", r);
	}
	return 0;
}
這幾天有些怠惰了,振作起來!