UVa 1632 Alibaba

本文介绍了一个关于阿里巴巴角色寻找宝藏的算法问题。该问题要求计算阿里巴巴如何在最短时间内收集所有带有时间限制的宝藏。文章提供了详细的算法实现过程,并讨论了递推方法的应用。

Alibaba the famous character of our childhood stories would like to be immortal in order to keep bringing happiness to children. In order to rich this status he needs to prove that he is still able to do some unusual things. There are n treasures, (n<=10000) each in a different place located along a straight road. Each treasure has a time limit, after that it vanishes. Alibaba must take all the n treasures, and he must do it quickly. So he needs to figure out the order in which he should take the treasures before their deadlines starting from the most favorable position. Alibaba has the list of places and deadlines of the treasures. A place i is located at distance di from the leftmost end of the road. The time it takes to take a treasure is instantaneous. Alibaba must find the smallest time by which he can take all the treasures.

Input 

The program input is from a text file. Each data set in the file stands for a particular set of treasures. For each set of treasures the input contains the number of treasures, and the list of pairs place - deadline in increasing order of the locations. White spaces can occur freely between the numbers in the input. The input data are correct.

Output 

For each set of data the program prints the result to the standard output on a separate line. The solution is represented by the smallest time by which Alibaba can take all the treasures before they vanish. If this is not possible then the output is "No solution".

Sample Input 

5
1 3
3 1
5 8
8 19
10 15

5
1 5
2 1
3 4
4 2
5 3

Sample Output 

11
No solution

#include <cstdio>
#include <cstring>
#include <utility>
#include <algorithm>
using namespace std;

//long long inf = (1<<30);
//long long inf = -1;
int inf = (1<<30);
// record[i][j][0]代表拿完第i,...,j的宝物,现在在第i点,所用最少时间
// record[i][j][1]代表拿完第i,...,j的宝物,现在在第j点,所用最少时间
//long long record[10010][10010][2];
int record[10010][10010][2];

// flag[i][j][k] == g_count 代表record[i][j][k]被计算过
//int flag[10010][10010][2];


int n;

//pair<long,long> array[10010];
pair<int,int> array[10010];
/*int dist[10010];
int time[10010];
*/
int g_count;


int get_min(int begin, int end, int k);

int main()
{
//	memset(flag, 0, sizeof(flag));
//	g_count = 1;
	while(scanf("%d", &n) == 1)
	{
		for(int i = 1; i <= n; i++)
		{
/*			long long x, y;
			scanf("%lld %lld", &x, &y);
			array[i] = pair<long long,long long>(x, y);
*/
			int x, y;
			scanf("%d%d", &x, &y);
			array[i] = pair<int,int>(x, y);
//			dist[i] = x;
//			time[i] = y;
			record[i][i][0] = 0;
			record[i][i][1] = 0;
		}	
		// 计算结果	
//		for(int k = 1; k <= n-1; k++)
		for(int i = n-1; i >= 1; i--)
		{
			for(int j = i+1; j <= n; j++)
//			for(int i = 1; i+k <= n; i++)
			{
//				int j = i+k;
/*		
				// 为0的情况,点在i.
				long long ans1 = -1;
				long long r1 = record[i+1][j][0];
				long long c1 = array[i+1].first - array[i].first;
				if(r1 != -1 && (r1+c1 <= array[i].second))
				{
					if(ans1 == -1)
                                                ans1 = r1+c1;
                                        else
                                                ans1 = min(ans1, r1+c1);
				}
				long long r2 = record[i+1][j][1];
                                long long c2 = array[j].first - array[i].first;
                                if(r2 != -1 && (r2+c2 <= array[i].second))
				{
					if(ans1 == -1)
                                                ans1 = r2+c2;
                                        else
                                                ans1 = min(ans1, r2+c2);
				}
				record[i][j][0] = ans1;
				
				// 为1的情况,点在j
				ans1 = -1;
				r1 = record[i][j-1][0];
                                c1 = array[j].first - array[i].first;
                                if(r1 != -1 && (r1+c1 <= array[j].second))
				{
					if(ans1 == -1)
						ans1 = r1+c1;
					else
						ans1 = min(ans1, r1+c1);
				}
                                r2 = record[i][j-1][1];
                                c2 = array[j].first - array[j-1].first;
                                if(r2 != -1 && (r2+c2 <= array[j].second))
                                {
					if(ans1 == -1)
                                                ans1 = r2+c2;
                                        else
                                                ans1 = min(ans1, r2+c2);
				}

				record[i][j][1] = ans1;
*/
				// 为0的情况,点在i.
                                int ans1 = inf;
                                int r1 = record[i+1][j][0];
                                int c1 = array[i+1].first - array[i].first;
                                if(r1 != inf && (r1+c1 < array[i].second))
                              	{
                                   	ans1 = min(ans1, r1+c1);
                                }
                                int r2 = record[i+1][j][1];
                                int c2 = array[j].first - array[i].first;
                                if(r2 != inf && (r2+c2 < array[i].second))
	                     	{
                                	ans1 = min(ans1, r2+c2);
                                }
                                record[i][j][0] = ans1;			

				// 为1的情况,点在j
                                ans1 = inf;
                                r1 = record[i][j-1][0];
                                c1 = array[j].first - array[i].first;
                                if(r1 != inf && (r1+c1 < array[j].second))
                                {
                                  	ans1 = min(ans1, r1+c1);
                                }
                                r2 = record[i][j-1][1];
                                c2 = array[j].first - array[j-1].first;
                                if(r2 != inf && (r2+c2 < array[j].second))
                                {
                               		ans1 = min(ans1, r2+c2);
                                }

                                record[i][j][1] = ans1;		

			}
		}		

		
//		int r = min(get_min(1, n, 0), get_min(1, n, 1));
/*		long long r1 = record[1][n][0];
		long long r2 = record[1][n][1];
		if(r1 == -1 && r2 == -1)
			printf("No solution\n");
		else if(r1 == -1 && r2 != -1)
			printf("%lld\n", r2);
		else if(r1 != -1 && r2 == -1)
                        printf("%lld\n", r1);
		else
			printf("%lld\n", min(r1,r2));		
*/
		int r = min(record[1][n][0], record[1][n][1]);
		if(r == inf)
			printf("No solution\n");
		else
			printf("%d\n", r);

//		g_count++;
	}
	return 0;
}

/*
// 计算结果     
// record[begin][end][0]代表拿完第begin,...,end的宝物,现在在第begin点,所用最少时间
// record[begin][end][1]代表拿完第begin,...,end的宝物,现在在第end点,所用最少时间
int get_min(int begin, int end, int k)
{
	if(flag[begin][end][k] == g_count)
		return record[begin][end][k];

	flag[begin][end][k] = g_count;

	if(begin == end)
	{
		record[begin][end][k] = 0;
		return record[begin][end][k];
	}

	int ans = inf;
	if(k == 0)
	{
		int r1 = get_min(begin+1, end, 0);
		int c1 = array[begin+1].first - array[begin].first;
		if(r1 != inf && r1+c1 <= array[begin].second)
			ans = min(ans, r1+c1);
		
		int r2 = get_min(begin+1, end, 1);
		int c2 = array[end].first - array[begin].first;
		if(r2 != inf && r2+c2 <= array[begin].second)
			ans = min(ans, r2+c2);
		record[begin][end][k] = ans;	
	}		
	else if(k == 1)
	{
		int r1 = get_min(begin, end-1, 0);
                int c1 = array[end].first - array[begin].first;
                if(r1 != inf && r1+c1 <= array[end].second)           
                        ans = min(ans, r1+c1);
                
                int r2 = get_min(begin, end-1, 1);
                int c2 = array[end].first - array[end-1].first;
                if(r2 != inf && r2+c2 <= array[end].second)
                        ans = min(ans, r2+c2);  
                record[begin][end][k] = ans;
	}
	return record[begin][end][k];
}
*/


这道题和前面一道机器人修复长城类似,很容易可以想到状态d(i, j, k)表示取完第i,...,j个宝物,在i(k=0)或j(k=1)处,所花最少时间。
这题故意设置n为一万,一开始用记忆化搜索,TLE.
后来改成递推,AC. 

感觉比较奇特的一点是,按照自己的方式递推(根据i和j之间的差值从1到n-1)
和汝佳书上方法(i从n-1到1,j从i+1到n), 时间花费多了一倍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值