(intermediate) 最短路 UVA 10841 - Lift Hopping in the Real World

Problem B
Lift Hopping in the Real World
Time Limit: 1 second

"I think problem descriptions should withstand the
reality check, otherwise they are misleading."

little joey

A skyscraper has no more than 100 floors, numbered from 0 to 99. It has n (1<=n<=50) elevators which travel up and down at (possibly) different speeds. For each i in {1, 2,... n}, elevator number i takes Ti (1<=Ti<=100) seconds to travel between any two adjacent floors (going up or down). Elevators do not necessarily stop on every floor. What's worse, not every floor is necessarily accessible by an elevator.

You are on floor 0 and would like to get to floor k as quickly as possible. When you first arrive to floor 0, each of the n elevators could be parked on any of the floors accessible by that elevator. You can take any of the elevators that stop on floor 0 and you can switch elevators on any floor, f, if both of them stop on floor f. Assume that it takes 5 seconds to exit one elevator and push another elevator's button. You are forbiden from using the staircase. No one else is in the building, so you don't have to stop if you don't want to, and no one else will request an elevator. Each elevator has its own button, and the system has built-in security to prevent abuse by evil teenagers - once you press the button calling for some elevator E, all the buttons calling for other elevators will be disabled until elevator E arrives at your floor. In other words, you can only call for one elevator at a time.

Calculate the number of seconds required to get from floor 0 to floor k in the worst case if you do not know the initial positions of the elevators. Passing floor k while inside an elevator that does not stop there does not count as "getting to floor k". See the examples below.

Input
The input will consist of a number of test cases. Each test case will begin with two numbers, n and k, on a line. The next line will contain the numbers T1, T2,... Tn. The next n lines will contain sorted lists of integers - the first line will list the floors visited by elevator number 1, the next one - those visited by elevator number 2, etc.

Output

For each test case, output one number on a line - the number of seconds required to get to floor k from floor 0 in the worst case. If floor k is inaccessible from floor 0, print "IMPOSSIBLE" instead.

Sample InputSample Output
2 30
10 5
0 1 3 5 7 9 11 13 15 20 99
4 13 15 19 20 25 30
2 30
10 1
0 5 10 12 14 20 25 30
2 4 6 8 10 12 14 22 25 28 29
3 50
10 50 100
0 10 30 40
0 20 30
0 20 50
1 1
2
0 2 4 6 8 10
1295
600
8505
IMPOSSIBLE

Discussion

In the first example, the worst case is when elevator 1 is on floor 99 and will take 990 seconds to reach floor 0. You will then take it to floor 13 in 130 seconds, spend 5 second exiting and calling elevator 2, which is on floor 30. It will take 170 seconds to reach you and 170 seconds to take you to floor 30. The total is 1295 seconds.

In the second example, the only sensible way to get to floor 30 is to ride the first elevator all the way. Switching to elevator 2 and then back will only make things worse because elevator 1 must take at least 300 seconds to reach floor 30. In the worst case, elevator 1 starts on floor 30.

In example 3, the security system will not allow you to push all 3 buttons and see which elevator comes first. Instead, you should push elevator 2's button. Unfortunately, it is on floor 30 and takes 1500 seconds to get to you. You board it and it takes you to floor 20 in 1000 seconds. You spend 5 seconds pushing the button for elevator 3, which is on floor 50. It takes 3000 seconds before it reaches floor 20 and 3000 more seconds to take you to floor 50. The total is 8505 seconds. If you take elevator 1 first, your worst case time will be 8710 seconds.

In the last example, the one elevator does not stop at floor 1.


Problemsetter: Igor Naverniouk



题意:你在一个有电梯的大楼里面,一开始你在第0层,然后你要坐电梯到第K层,其中每一次只能坐一架电梯,并且每一次只能有一架电梯能动,每个电梯有各自的运动速度,每一次换电梯需要耗费5秒,一开始你也不知道电梯在哪一层,问最差的情况下,到达第K层的最短时间。


思路:首先我们可以确定每一架电梯我们只会乘坐一次,因为如果我们又回来乘坐这个电梯到别的地方,倒不如一开始就乘坐到那个地方,因为整个过程的时间相当于是电梯的运动时间,你假设想从s->t,如果你乘坐电梯时中途出去了,有坐别的电梯,然后回来继续坐这个电梯到t,显然时间花费长了,而这架电梯仍然要从s->t,这家电梯花掉你的时间是一样的。所以每架电梯我们只会乘坐一次。求最短路可以用Dijkstra算法,我们开始设计状态,对于最多只有50架电梯,我们能用一个long long(64bit)存储下来,1代表用过了,0代表没用过。开始状态时全为0,距离是-5(好处理一点),注意如果目标地点是0的话,加个0的特判。然后就可以开始搜索了,因为我这里刚开始还用了个Floyd求出任意两点的最短距离(不包括等电梯的时间),所以我们除了记录当前状态已经消耗的时间,还要记录从当前状态到目标最少可能还要花多少时间。让优先队列根据两个时间的和来排序。比不加会好一点。不过,这个。。。就变成了A*算法了。其实我觉得可能直接用floyd就能求出来了。。。。。不过不管了。


代码:

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<stack>
#include<list>
#include<cstring>
#include<vector>
using namespace std;
#define LL long long
#define eps 1e-10
#define mp make_pair
#define MOD 10007
const int maxn = 100 + 5;
const int inf = 1e7;
int n, K;
int T[maxn];
vector<int> G[maxn];
vector<int> elevator[maxn];
int minfloor[maxn];
int maxfloor[maxn];
int w[maxn][maxn];
vector<int> Fill;
bool fillin[MOD];

struct State
{
	int g;
	int h;
	LL use;
	int floor;
	int evt;
	bool operator<(const State&st) const { return g+h>st.h+st.g; }
	bool equals(const State&st) const
	{
		if (floor != st.floor) return false;
		return use == st.use;
	}
};


list<State> hsh[MOD];

void init()
{
	for (int i = 0; i < Fill.size(); ++i)
	{
		hsh[Fill[i]].clear();
		fillin[Fill[i]] = false;
	}
	Fill.clear();
//	for (int i = 0; i < MOD; ++i) if (hsh[i].size())
//		hsh[i].clear();
}

LL Key(const State&st)
{
	return ((abs(K - st.floor) * 131313)%MOD+st.use%MOD)%MOD;
}

typedef list<State>::iterator Iter;
bool Insert(const State &st)
{
	int k = Key(st), i;
//	printf("%d\n", k);
	for (Iter it = hsh[k].begin(); it !=hsh[k].end(); ++it)
	{
		if (st.equals(*it))
		{
			if (st.g+st.h >=it->g+it->h) return false;
			it->g = st.g;
			it->h = st.h;
			return true;
		}
	}
	if (!fillin[k])
	{
		Fill.push_back(k);
		fillin[k] = true;
	}
	hsh[k].push_back(st);
	return true;
}


char in[1000];
void input()
{
	for (int i = 0; i < 100;++i)
	for (int j = 0; j < 100; ++j)
		w[i][j] = inf;
	for (int i = 0; i < 100; ++i) w[i][i] = 0;
	for (int i = 0; i < 100; ++i) elevator[i].clear();
	for (int i = 0; i < n; ++i) {
		scanf("%d", T + i);
		G[i].clear();
	}
	memset(minfloor, 0x3f, sizeof(minfloor));
	memset(maxfloor, -1, sizeof(maxfloor));
	vector<int> V;
	getchar();
	for (int i = 0; i < n; ++i)
	{
		gets(in);
		char *p = strtok(in, " ");
		vector<int> v;
		while (p != NULL)
		{
			int x; sscanf(p, "%d", &x);
			v.push_back(x);
			V.push_back(x);
			G[i].push_back(x);
			elevator[x].push_back(i);
			minfloor[i] = min(minfloor[i], x);
			maxfloor[i] = max(maxfloor[i], x);
			p = strtok(NULL, " ");
		}
		for (int j = 0; j < v.size();++j)
		for (int k = j+1; k < v.size(); ++k)
		{
			int x = v[j], y = v[k];
			w[x][y] = w[y][x] = min(w[x][y], min(w[y][x], (y - x)*T[i]));
		}
	}
	sort(V.begin(), V.end());
	int C = unique(V.begin(), V.end())-V.begin();
	for (int k = 0; k < C; ++k)
	for (int i = 0; i < C; ++i)
	for (int j = 0; j < C; ++j)
		w[V[i]][V[j]] = min(w[V[i]][V[j]], w[V[i]][V[k]] + w[V[k]][V[j]] + 5);
}

int Dijkstra(State& s)
{
	priority_queue<State> q;
	q.push(s);
	init();
	Insert(s);
	while (q.size())
	{
		State temp = q.top(); q.pop();
		int floor = temp.floor;
		if (floor == K) return temp.g;
		for (int i = 0; i < elevator[floor].size(); ++i)
		{
			int g = temp.g+5;
			int x = elevator[floor][i];
			if (x == temp.evt) continue;
			if (temp.use&((LL)1 << x)) continue;
			g += max(floor-minfloor[x],maxfloor[x]-floor)*T[x];
			for (int j = 0; j < G[x].size(); ++j)
			{
				int y = G[x][j];
				State now = temp;
				now.g = g+abs(y - floor)*T[x];
				now.evt = x;
				now.use |= ((LL)1 << x);
				now.floor = y;
				now.h = w[y][K];
				if (Insert(now)) q.push(now);
			}
		}
	}
	return -1;
}

void solve()
{
	if (K == 0) { printf("0\n"); return; }
//	printf("%d\n", w[0][K]);
//	printf("%d\n", w[K][K]);
	if (w[0][K] >= inf)
	{
		puts("IMPOSSIBLE");
		return;
	}
	State start;
	start.g = -5;
	start.evt = -1;
	start.floor = 0;
	start.use = 0;
	start.h = w[0][K];
	int ans = Dijkstra(start);
	if (ans == -1) printf("IMPOSSIBLE\n");
	else printf("%d\n", ans);
}

int main()
{
	while (scanf("%d%d", &n, &K) == 2)
	{
		input();
		solve();
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值