Cod sursa(job #508030)

Utilizator pauldbPaul-Dan Baltescu pauldb Data 7 decembrie 2010 13:59:21
Problema Magazin Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.73 kb
#include <cstdio>
#include <algorithm>
#include <cassert>

using namespace std;

const int MAX_PRODUCTS = 50010;
const int MAX_WIDTH = 30010;
const int MAX_STATES = 6;
const int INFINITY = 100000000;

int noProducts, width, height, distBetweenCols;
pair <int, int> products[MAX_PRODUCTS];
int minHeight[MAX_WIDTH], maxHeight[MAX_WIDTH], maxHeightDist[MAX_WIDTH];
int dp[MAX_WIDTH][MAX_STATES];

void read() {
	freopen("magazin.in", "r", stdin);

	scanf("%d %d %d %d", &noProducts, &width, &height, &distBetweenCols);

	for (int i = 1; i <= noProducts; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		products[i] = make_pair(x, y);
	}
}

void preprocess() {
	sort(products+1, products+noProducts+1);

	for (int i = 1, j = 1; i <= width; ++i) {
		minHeight[i] = height+1;
		maxHeight[i] = 0;

		int lastHeight = 0;

		while (j <= noProducts && products[j].first == i) {
			minHeight[i] = min(minHeight[i], products[j].second);
			maxHeight[i] = max(maxHeight[i], products[j].second);
			maxHeightDist[i] = max(maxHeightDist[i], products[j].second-lastHeight);
			lastHeight = products[j].second;
			++j;
		}

		maxHeightDist[i] = max(maxHeightDist[i], height+1-lastHeight);
	}
}

int countColumnPass(int prevState, int nextState) {
	if ((prevState ^ nextState) & 1)
		return 1;
	return 2;
}

int calcTravelDistPerCol(int prevState, int nextState, int col) {
	int factor = countColumnPass(prevState, nextState);

	if ((prevState ^ nextState) & 1)
		return factor*(height+1);

	if (prevState < 4 && nextState >= 4)
		return factor*(height+1);

	if ((prevState >= 2 && prevState < 4) && nextState < 2)
		return factor*(height+1);

	if (nextState >= 2 || prevState >= 2)
		return 2*((height+1) - maxHeightDist[col]);

	if (nextState == 1)
		return 2*maxHeight[col];
	
	if (nextState == 0)
		return 2*(height+1-minHeight[col]);

	return 0;
}

int calcTravelDistBetweenCols(int nextState) {
	if (nextState >= 2)
		return 3;
	return 1;
}

void doDP() {
	const int noValidStates[MAX_STATES] = {5, 5, 5, 5, 2, 2};
	const int validStates[MAX_STATES][MAX_STATES] = {
		{0, 1, 2, 4, 5}, 
		{0, 1, 3, 4, 5}, 
		{0, 1, 2, 4, 5},
		{0, 1, 3, 4, 5},
		{0, 4},
		{1, 5}
	};

	for (int i = 0; i <= width; ++i)
		for (int j = 0; j < MAX_STATES; ++j)
			dp[i][j] = INFINITY;
	dp[0][1] = 0;

	for (int i = 0; i < width; ++i)
		for (int j = 0; j < MAX_STATES; ++j)
			for (int k = 0; k < noValidStates[j]; ++k) {
				dp[i+1][validStates[j][k]] = min(dp[i+1][validStates[j][k]], dp[i][j] +
				calcTravelDistPerCol(j, validStates[j][k], i+1) + distBetweenCols *
				calcTravelDistBetweenCols(validStates[j][k]));
			}
}

void solve() {
	preprocess();
	doDP();
}

void write() {
	freopen("magazin.out", "w", stdout);

	printf("%d\n", dp[width][1]-distBetweenCols);
}

int main() {
	read();
	solve();
	write();
	return 0;
}