列表

详情


NC24036. [USACO 2016 Jan P]Lights Out

描述

Farmer John has installed a fancy new milking machine in his barn, but it draws so much power that it occasionally causes the power to go out! This happens so often that Bessie has memorized a map of the barn, making it easier for her to find the exit of the barn in the dark. She is curious though about the impact of power loss on her ability to exit the barn quickly. For example, she wonders how much farther she might need to walk find the exit in the dark.
The barn is described by a simple (non self-intersecting) polygon with integer vertices (x1,y1)…(xn,yn) listed in clockwise order. Its edges alternate between horizontal (parallel to the x-axis) and vertical (parallel to the y-axis); the first edge can be of either type. The exit is located at (x1,y1). Bessie starts inside the barn located at some vertex (xi,yi) for i>1. She can walk only around the perimeter of the barn, either clockwise or counterclockwise, potentially changing direction any time she reaches a vertex. Her goal is to travel a minimum distance to reach the exit. This is relatively easy to do with the lights on, of course, since she will travel either clockwise or counterclockwise from her current location to the exit -- whichever direction is shorter.

One day, the lights go out, causing Bessie to panic and forget which vertex she is standing at. Fortunately, she still remembers the exact map of the barn, so she can possibly figure out her position by walking around and using her sense of touch. Whenever she is standing at a vertex (including at her initial vertex), she can feel whether it is a left turn or a right turn, and she can tell if that vertex is the exit. When she walks along an edge of the barn, she can determine the exact length of the edge after walking along the entire edge. In general, Bessie will strategically feel her way around her starting vertex until she knows enough information to determine where she is, at which point she can easily figure out how to get to the exit by traveling a minimum amount of remaining distance.

Please help Bessie determine the smallest possible amount by which her travel distance will increase in the worst case (over all possibilities for her starting vertex) for travel in the dark versus in a lit barn, assuming she moves according to an optimal strategy in each case. An "optimal" strategy for the unlit case is one that minimizes this extra worst-case amount.

输入描述

The first line of the input contains N (4≤N≤200). Each of the next N lines contains two integers, describing the points (xi,yi) in clockwise order around the barn. These integers are in the range −100,000…100,000.

输出描述

Please output the smallest possible worst-case amount by which Bessie's optimal distance in the dark is longer than her optimal distance in a lit barn, where the worst case is taken over all possible vertices at which Bessie can start.

示例1

输入:

4
0 0
0 10
1 10
1 0

输出:

2

说明:

In this example, Bessie can feel that she is initially standing at an inward bend, however since in this example all corners are inward bends this tells her little information.

One optimal strategy is to just travel clockwise. This is optimal is she starts at vertex 3 or 4 and only adds 2 units of distance if she starts at vertex 2.

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

Python3(3.9) 解法, 执行用时: 740ms, 内存消耗: 3320K, 提交时间: 2020-12-21 19:23:30

N = int(input())
vertices = []
dists = []
prev = None
for _ in range(N):
    s, t = tuple(map(int, input().split()))
    if vertices:
        dists.append(abs(vertices[-1][0] - s) + abs(vertices[-1][1] - t))
    vertices.append((s, t))
# dist between last vertex and first
dists.append(abs(vertices[0][0] - vertices[-1][0]) + \
             abs(vertices[0][1] - vertices[-1][1]))
 
angles = []  # records the angle at the vertex
for i in range(N):
    prev, cur, nxt = vertices[i - 1], vertices[i], vertices[(i + 1) % N]
    if prev[1] == cur[1] and prev[0] > cur[0] and cur[0] == nxt[0] and cur[1] < nxt[1]:
        angles.append(1)
    elif prev[0] == cur[0] and prev[1] < cur[1] and cur[1] == nxt[1] and cur[0] < nxt[0]:
        angles.append(1)
    elif prev[1] == cur[1] and prev[0] < cur[0] and cur[0] == nxt[0] and cur[1] > nxt[1]:
        angles.append(1)
    elif prev[0] == cur[0] and prev[1] > cur[1] and cur[1] == nxt[1] and cur[0] > nxt[0]:
        angles.append(1)
    else:
        angles.append(-1)

def main():
    indices = range(1, N)
    possibilities = {}
    max_cost = 0
    for i in indices:
        knowledge = angles[i]
        if knowledge in possibilities:
            possibilities[knowledge].append(i)
        else:
            possibilities[knowledge] = [i]

    for _, indices in possibilities.items():
        if len(indices) == 1:
            continue
        else:
            max_cost = max(max_cost, left_right_search(indices))
    print(max_cost)

def find_cost(index, shift):
    optimal_dist = min(sum(dists[index:]), sum(dists[:index]))
    optimal_dist_for_shifted_index = min(sum(dists[index+shift:]), sum(dists[:index+shift]))
    return optimal_dist_for_shifted_index - optimal_dist

def left_right_search(indices, shift=0):
    max_left_cost = left_search(indices, shift=shift)
    max_right_cost = right_search(indices, shift=shift)
    return min(max_left_cost, max_right_cost)

def left_search(indices, shift):
    #left is anti-clockwise LOL
    n = len(indices)
    possibilities = {}
    shift -= 1
    max_cost = -1e9
    for i in indices:
        if i + shift == 0:
            continue
        knowledge = angles[i+shift] * dists[i+shift]
        if knowledge in possibilities:
            possibilities[knowledge].append(i)
        else:
            possibilities[knowledge] = [i]

    for knowledge, indices in possibilities.items():
        if len(indices) == 1:
            max_cost = max(max_cost, abs(knowledge) + find_cost(indices[0], shift))
        elif len(indices) == n:
            max_cost = max(max_cost, abs(knowledge) + left_search(indices, shift))
        else:
            max_cost = max(max_cost, abs(knowledge) + left_right_search(indices, shift))

    return max_cost

def right_search(indices, shift):
    #left is anti-clockwise LOL
    n = len(indices)
    possibilities = {}
    shift += 1
    max_cost = -1e9
    for i in indices:
        if i + shift == N:
            continue
        knowledge = angles[i+shift] * dists[i+shift-1]
        if knowledge in possibilities:
            possibilities[knowledge].append(i)
        else:
            possibilities[knowledge] = [i]

    for knowledge, indices in possibilities.items():
        if len(indices) == 1:
            max_cost = max(max_cost, abs(knowledge) + find_cost(indices[0], shift))
        elif len(indices) == n:
            max_cost = max(max_cost, abs(knowledge) + right_search(indices, shift))
        else:
            max_cost = max(max_cost, abs(knowledge) + left_right_search(indices, shift))

    return max_cost          
               
main()

C++(clang++11) 解法, 执行用时: 42ms, 内存消耗: 37296K, 提交时间: 2020-12-20 12:50:22

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define MAXN 210
#define INF 0x3FFFFFFF
int opt[MAXN];
int psum[MAXN];
int canon[MAXN*2][MAXN*2];
vector<int> lparents[MAXN][MAXN];
vector<int> rparents[MAXN][MAXN];
int dp[MAXN][MAXN][MAXN][2];
int main() {
	int N;
	cin >> N;
	vector<pair<long long, long long> > A(N);
	for (int i = 0; i < N; i++) {
		cin >> A[i].first >> A[i].second;
	}
	vector<int> S(1, 0);
	for (int i = 0; i < N; i++) {
		int j = (i + 1) % N;
		int k = (i + 2) % N;
		S.push_back(abs(A[i].first - A[j].first) +abs(A[i].second - A[j].second));
		if ((A[i].first - A[j].first) * (A[k].second - A[j].second) - (A[k].first - A[j].first) * (A[i].second - A[j].second) > 0) {
			S.push_back(-1);
		} else {
			S.push_back(-2);
		}
	}
	S.back() = 0;
	for (int i = 0; i < N; i++) {
		psum[i + 1] = opt[i + 1] = opt[i] + S[2 * i + 1];
	}
	opt[N] = 0;
	for (int i = N - 1; i >= 0; i--) {
		opt[i] = min(opt[i], opt[i + 1] + S[2 * i + 1]);
	}
	for (int ln = 1; ln <= S.size(); ln++) {
		for (int i = 0; i + ln <= S.size(); i++) {
			for (int& j = canon[i][ln]; j < i; j++) {
				if (canon[j][ln - 1] == canon[i][ln - 1] && S[j + ln - 1] == S[i + ln - 1]) {
					break;
				}
			}
		}
	}
	for (int i = 0; i < S.size(); i += 2) {
		for (int ln = 3; i + ln <= S.size(); ln += 2) {
			if (i != canon[i][ln]) {
				continue;
			}
			lparents[canon[i + 2][ln - 2] / 2][ln / 2].push_back(i / 2);
			rparents[canon[i][ln - 2] / 2][ln / 2].push_back(i / 2);
		}
	}
	int result = 0;
	for (int ln = N; ln >= 1; ln--) {
		for (int i = 0; i + ln <= N + 1; i++) {
			if (canon[2 * i][2 * ln - 1] != 2 * i) {
				continue;
			}
			int dist_across = psum[i + ln - 1] - psum[i];
			for (int strt = 0; strt < ln; strt++) {
				for (int side = 0; side < 2; side++) {
					if (i == 0 || i + ln == N + 1) {
						dp[i][ln][strt][side] = -opt[i + strt];
						continue;
					}
					int lft_cst = -INF;
					vector<int>::iterator it;
					for(it=lparents[i][ln].begin(); it!=lparents[i][ln].end(); it++) {
						lft_cst = max(lft_cst, S[2 * (*it) + 1] + dp[(*it)][ln + 1][strt + 1][0]);
					}
					int rht_cst = -INF;
					for(it= rparents[i][ln].begin(); it!=rparents[i][ln].end(); it++) {
						rht_cst = max(rht_cst,S[2 * ((*it) + ln) - 1] + dp[(*it)][ln + 1][strt][1]);
					}
					(side ? lft_cst : rht_cst) += dist_across;
					dp[i][ln][strt][side] = min(lft_cst, rht_cst);
					if (ln == 1) {
						result = max(result, dp[i][ln][strt][side]);
					}
				}
			}
		}
	}
	cout << result << endl;
	return 0;
}

上一题