算法刷题记录(Day 42)

Sightseeing Cows(poj 3261)

原题链接

题目类型:最优比率环

思考过程:
存在的限制:
1.起始点是不确定的
2.对于某一个地标,第一次到达时具有乐趣,后续不具备乐趣
3.最少要去两个地标
存在的问题:
1.a为乐趣,b为时间,如何将a和b进行对应?存在第二次达到的问题,那么这是一个动态对映的过程吗?
2.如何去找到一条可行的路径(环)?即如何去寻找到一个可行的解?

在这篇题解中,认定了答案是不可能为两个环的交的形式的,但是不知道为什么???

参考题解

假设答案的最终形式一定不会是两个环的交,即一定是一个简单环时,应该如何求解呢?
0/1规划的思路在于二分,为此我们设置L、R和M,并对于M进行检验以更新最终的结果。

那么如何进行检验呢?
假设存在一个环r,使得fun-rcost>0,即L更新为M,否则R更新为M。对于fun-rcost>0,转化为rcost-fun<0,即在边值为边值为rcost-fun的图(每一条边和其进入的点相挂钩)中,是否存在一个负权环?->使用spfa判断即可。

#include
#include
#include
using namespace std;
#define LMAX 1010
#define EPS 1e-6
#define INF 1e9
int L, P;
int fun[LMAX];

vector<vector<pair<int,int > > > E(LMAX);
int spfa(double ans) {
	int vis[LMAX];
	double dis[LMAX];
	int num[LMAX];
	for (int i = 1; i <= L; i++) {
		vis[i] = 0;
		num[i] = 0;
		dis[i] = INF;
	}
	queue<int > Q;
	Q.push(1);
	vis[1] = 1, dis[1] = 0;
	num[1]++;
	while (!Q.empty()) {
		int u = Q.front();
		Q.pop();
		vis[u] = 0;
		for (int i = 0; i < E[u].size(); i++) {
			int v = E[u][i].first;
			int w = E[u][i].second;
			if (dis[u] + ans * w - fun[v] < dis[v]) {
				dis[v] = dis[u] + ans * w - fun[v];
				if (!vis[v]) {
					Q.push(v);
					num[v]++;
					if (num[v] == L) return 1;
				}
			}
		}
	}
	return 0;
}
int main() {
	cin >> L >> P;
	for (int i = 1; i <= L; i++) scanf_s("%d", &fun[i]);
	for (int i = 0; i < P; i++) {
		int f, t, w;
		scanf_s("%d %d %d", &f, &t, &w);
		E[f].push_back(make_pair(t, w));
	}
	double L = 0, R = 1000, M;
	while (R - L > EPS) {
		M = (L + R) / 2;
		//printf("%.2f %.2f %.2f\n", L, M, R);
		if (spfa(M)) L = M;
		else R = M;
	}

	printf("%.2f\n", L);
}

tip:
1.spfa判断环的方式是某个节点的入队次数不应该达到总的点数

Texas Trip(poj 3301)

原题链接
题目类型:迭代逼近

二分查找针对的是单调函数的定位问题,三分查找针对的则是二次函数的定位问题。可以这样理解,在0/1规划中,使用二分的方式是将L、R为结果数,而此题中的L、R则为方案数,最终通过某个方案得到的解才为真正的结果数。

如何体现覆盖:
已知最大的横坐标差为x_max,最大的纵坐标差为y_max,max=max(x_max,y_max),则必然存在一个边和x、y轴平行的正方型,能够完全覆盖所有的点。

如何体现最小性:
将正方形进行旋转寻找最小的覆盖是困难的,但是由于点的位置都是相对的,因此可以将所有的点旋转,对于每一个角度,都存在一个覆盖,寻找最小的覆盖即可。

由于角度对于正方形的面积来说不是一个单调的函数,且角度是方案而不是最终的结果,因此必须选择三分的方式。
三分算法

坐标旋转公式

等三分会WA

#include
#include
using namespace std;
#define TMAX 33
int T, n;
double dot[TMAX][2];
double dot2[TMAX][2];
double cac(double ang) {
	double x_max = 0, y_max = 0;
	for (int i = 0; i < n; i++) {
		dot2[i][0] = cos(ang) * dot[i][0] - sin(ang) * dot[i][1];
		dot2[i][1] = sin(ang) * dot[i][0] + cos(ang) * dot[i][1];
	}
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			if (fabs(dot2[i][0] - dot2[j][0]) > x_max) x_max = fabs(dot2[i][0] - dot2[j][0]);
			if (fabs(dot2[i][1] - dot2[j][1]) > y_max) y_max = fabs(dot2[i][1] - dot2[j][1]);
		}
	}
	return max(x_max, y_max) * max(x_max, y_max);
}
int main() {
	scanf_s("%d", &T);
	while (T--) {
		
		scanf_s("%d", &n);
		for (int i = 0; i < n; i++) scanf_s("%lf %lf", &dot[i][0], &dot[i][1]);
		
		double L = 0, R = asin(1), M1, M2;
		while (R - L > 1e-7) {
			M1 = L + (R - L) / 3;
			M2 = R - (R - L) / 3;
			if (cac(M2) < cac(M1)) L = M1;
			else R = M2;
			//printf("%.2f %.2f %.7f\n", L, R, R-L);
		}

		printf("%.2f\n", cac(L));
	}
}

二分然后再二分能够AC

#include
#include
using namespace std;
#define TMAX 33
int T, n;
double dot[TMAX][2];
double dot2[TMAX][2];
double cac(double ang) {
	double x_max = 0, y_max = 0;
	for (int i = 0; i < n; i++) {
		dot2[i][0] = cos(ang) * dot[i][0] - sin(ang) * dot[i][1];
		dot2[i][1] = sin(ang) * dot[i][0] + cos(ang) * dot[i][1];
	}
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			if (fabs(dot2[i][0] - dot2[j][0]) > x_max) x_max = fabs(dot2[i][0] - dot2[j][0]);
			if (fabs(dot2[i][1] - dot2[j][1]) > y_max) y_max = fabs(dot2[i][1] - dot2[j][1]);
		}
	}
	//cout <
	return max(x_max, y_max) * max(x_max, y_max);
}
int main() {
	scanf_s("%d", &T);
	while (T--) {
		
		scanf_s("%d", &n);
		for (int i = 0; i < n; i++) scanf_s("%lf %lf", &dot[i][0], &dot[i][1]);
		
		double L = 0, R = asin(double(1)), M1, M2;
		while (R - L > 1e-12) {
			//M1 = L + (R - L) / 3;
			//M2 = R - (R - L) / 3;
			//printf("%.2f %.2f %.7f\n", L, R, R - L);
			M1 = (L + R) / 2.0;
			M2 = (R + M1) / 2.0;

			if (cac(M2) <= cac(M1)) L = M1;
			else R = M2;
			
		}

		printf("%.2f\n", cac(L));
	}
}

你可能感兴趣的:(算法刷题记录,算法)