November Rain

صورت سوال

مراجعه شود به http://acm.tju.edu.cn/toj/showp1879.html.

توضیح و بررسی

حل این مساله دو گام دارد:

  • گام اول: پیدا کردن اینکه هر طاقی از کدام طاق ها آب دریافت می کند و اینکه هر طاقی چقدر آب مستقیم از آسمان دریافت می کند.
  • گام دوم: پیدا کردن اینکه هر طاقی در کل چقدر آب دریافت می کند.

دو روش برای گام اول به ذهن من رسید:

  • روش اول: دارای پیچیدگی زمانی O(nm) است که n تعداد طاق ها و m حداکثر تعداد طاق بالای یک نقطه روی محور x هاست. این روش در حالت کلی بد است ولی چون در این مساله m حداکثر 25 است، برای این مساله کافی است.
  • روش دوم: دارای پیچیدگی زمانی O(n~log m) است.

برای گام دوم نیز دو راه وجود دارد:

  • برنامه سازی پویای بازگشتی
  • Toplogical Sort و برنامه سازی پویای Iterative

پیچیدگی زمانی هر دو روش یکسان است، ولی مشکلی که ممکن است برای روش یک بوجود آید این است که با خطای Stack Overflow مواجه شویم (البته متاسفانه داده های تست این مساله طوری است که این خطا رخ نمی دهد!)

(ناقص است)

کد من برای حل این سوال

#include <iostream>
#include <stack>
#include <cstdio>
#include <set>
#include <algorithm>
#include <vector>
using namespace std;
 
struct P{
	int first, second, third, fourth;
	P(){};
	P(int _f, int _s, int _t, int _ff):first(_f), second(_s), third(_t), fourth(_ff){}
	bool operator<(const P& p) const
	{
		if(first != p.first)
			return first < p.first;
		if(fourth == 1 && p.fourth == 0)
			return true;
		else if(fourth == 0 && p.fourth == 1)
			return false;
		if(fourth == 0 && p.fourth == 0)
			return third > p.third;
		else
			return third < p.third;
	}
};
 
#define vp vector<P>
#define vi vector<int>
 
int n;
int X1[40000], X2[40000], Y1[40000], Y2[40000];
 
vp v;
 
vi graph[40000];
int pure[40000];
 
int order[40000];
bool done[40000];
 
void topologicalSort()
{
	int idx = 0;
	stack<int> st;
	memset(done, 0, sizeof done);
	for(int i = 0; i < n; i ++)
		if(!done[i])
		{
			st.push(i);
			while(!st.empty())
			{
				int t = st.top();
				bool can_be_done = true;
				for(int j = 0; j < graph[t].size(); j ++)
					if(!done[graph[t][j]])
					{
						st.push(graph[t][j]);
						can_be_done = false;
					}
				if(can_be_done)
				{
					order[idx++] = t;
					done[t] = true;
					st.pop();
				}
			}
		}
}
 
int fallingSide(int idx)
{
	if(Y1[idx] > Y2[idx])
		return X2[idx];
	else
		return X1[idx];
}
 
double getY(int idx, int x)
{
	if(X1[idx] == x)
		return Y1[idx];
	else if(X2[idx] == x)
		return Y2[idx];
	double result = (Y2[idx] - Y1[idx]);
	result /= (X2[idx] - X1[idx]);
	result *= (x - X1[idx]);
	result += Y1[idx];
	return result;
}
 
int main()
{
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
	{
		scanf("%d %d %d %d", X1 + i, Y1 + i, X2 + i, Y2 + i);
		v.push_back(P(X1[i], i, Y1[i], 1));
		v.push_back(P(X2[i], i + 1000000, Y2[i], 0));
	}
	sort(v.begin(), v.end());
	memset(pure, 0, sizeof pure);
 
	set<int> st;
 
	int LastMax = -1;
	for(int i = 0; i < v.size(); i ++)
	{
		// 1. update LastMax's pure
		if(LastMax != -1)
			pure[LastMax] += v[i].first - v[i-1].first;
 
		// 2. append or remove the current item
		if(v[i].second >= 1000000)
		{
			st.erase(v[i].second - 1000000);
			v[i].second -= 1000000;
		}
		else
			st.insert(v[i].second);
 
		double myY = getY(v[i].second, v[i].first);
 
		int itemBelow = -1;
		double itemBelowY = 0;
		LastMax = -1;
		double LastMaxY = 0;
		// 3. Find the one below current item and update the LastMax
		for(set<int>::iterator it = st.begin(); it != st.end(); it ++)
		{
			double Y = getY(*it, v[i].first);
			if(LastMax == -1 || LastMaxY < Y)
			{
				LastMax = *it;
				LastMaxY = Y;
			}
			if(*it != v[i].second)
				if(Y < myY)
					if(itemBelow == -1 || itemBelowY < Y)
					{
						itemBelow = *it;
						itemBelowY = Y;
					}
		}
 
		// 4. Update the graph if on the falling side
		if(itemBelow != -1 && fallingSide(v[i].second) == v[i].first)
		{
			graph[itemBelow].push_back(v[i].second);
			//~ cout << v[i].second << " to " << itemBelow << endl;
		}
	}
 
	topologicalSort();
 
	for(int i = 0; i < n; i ++)
	{
		int t = order[i];
		for(int j = 0; j < graph[t].size(); j ++)
			pure[t] += pure[graph[t][j]];
	}
 
	for(int i = 0; i < n; i ++)
		cout << pure[i] << endl;
 
	return 0;
}

 
november_rain.txt · Last modified: 2008/01/07 19:14 by hadi
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki