BZOJ 3627 JLOI 2014 路径规划 分层图 SPFA+HEAP

题目大意:N个点M条无向边,每个点有可能有红绿灯,或者是加油站,或者单单是一个点。红绿灯太多会让人烦,太久不加油车子就会开不动,问最多通过K次红绿灯,从“start”点到“end”点的最少花费是多少。


思路:只能最多通过K次红绿灯,可以依据这个建分层图。f[ i ][ j ]为在已经通过i次红绿灯后,在j点时的最小花费。这只是总体的思路,具体是实现起来还是有其他一些小问题。

题目中有一个limit,表示从一个加油站到另一个加油站不能行驶超过这么远。仔细想想,其实那些不是加油站的点对我们来说没什么意义。经过简单的处理即可把他们处理掉。以每个加油站为起点进行SPFA,计算出这个节点到其他节点的距离和经过了多少红绿灯。把这些信息加入新图中,再从起点到终点跑一次SPFA就可以得到答案。

另外,红绿灯的等待时间取得是数学期望,简单画图像可得time = (red * red) / (2 * (red + green))


CODE:


#include <map>
#include <queue>
#include <cstdio>
#include <string>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
#define INF 0x7f7f7f7f
using namespace std;

map<string,int> G;
map<int,int> gas_num;

double f[11][MAX];
bool v[11][MAX];

struct Complex{
	int pos,step;
	Complex(int _step,int _pos):pos(_pos),step(_step) {}
	Complex() {}
	bool operator <(const Complex& a)const {
		return f[step][pos] > f[a.step][a.pos];
	}
};

int points,edges,k,limit,cost;
int st,ed;
int total_gas;
double expection[MAX];
bool stop[MAX],is_gas[MAX];
int head[MAX],total;
int next[MAX],aim[MAX];
double length[MAX];

int _head[MAX],_total;
int _next[MAX],_aim[MAX];
int lights[MAX];
double _length[MAX];

string temp;

inline void Add(int x,int y,double len);
inline void _Add(int x,int y,double _len,int l);
inline void _SPFA(int start);
void SPFA();

int main()
{
	cin >> points >> edges >> k >> limit >> cost;
	for(int x,y,i = 1;i <= points; ++i) {
		cin >> temp;
		G[temp] = i;
		if(temp == "start")	st = i,is_gas[i] = true;
		if(temp == "end")	ed = i,is_gas[i] = true;
		if(temp.find("gas") != string::npos)	is_gas[i] = true;
		scanf("%d%d",&x,&y);
		if(x) {
			expection[i] = (double)(x * x) / (2.0 * (x + y));
			stop[i] = true;
		}
	}
	for(int x,y,len,i = 1;i <= edges; ++i) {
		cin >> temp; x = G[temp];
		cin >> temp; y = G[temp];
		cin >> temp >> len;
		Add(x,y,(double)len + expection[y]),Add(y,x,(double)len + expection[x]);
	}
	for(int i = 1;i <= points; ++i)
		if(is_gas[i])	_SPFA(i);
	SPFA();
	double ans = INF;
	for(int i = 0;i <= k; ++i)
		ans = min(ans,f[i][ed]);
	cout << fixed << setprecision(3) << ans - cost;
	return 0;
}

inline void Add(int x,int y,double len)
{
	next[++total] = head[x];
	aim[total] = y;
	length[total] = len;
	head[x] = total;
}

inline void _Add(int x,int y,double len,int l)
{
	_next[++_total] = _head[x];
	_aim[_total] = y;
	_length[_total] = len;
	lights[_total] = l;
	_head[x] = _total;
}

inline void _SPFA(int start)
{
	static priority_queue<Complex> q;
	while(!q.empty())	q.pop();
	memset(f,0x43,sizeof(f));
	memset(v,false,sizeof(v));
	f[0][start] = 0;
	q.push(Complex(0,start));
	while(!q.empty()) {
		Complex temp = q.top(); q.pop();
		int x = temp.pos,step = temp.step;
		v[step][x] = false;
		for(int i = head[x];i;i = next[i]) {
			bool detla = stop[aim[i]];
			if(step + detla <= k && f[step + detla][aim[i]] > f[step][x] + length[i]) {
				f[step + detla][aim[i]] = f[step][x] + length[i];
				if(!v[step + detla][aim[i]]) {
					v[step + detla][aim[i]] = true;
					q.push(Complex(step + detla,aim[i]));
				}
			}
		}
	}
	for(int i = 0;i <= k; ++i)
		for(int j = 1;j <= points; ++j)
			if(j != start && f[i][j] <= limit && is_gas[j])
				_Add(start,j,f[i][j] + cost,i);
}

void SPFA()
{
	static priority_queue<Complex> q;
	memset(f,0x43,sizeof(f));
	memset(v,false,sizeof(v));
	f[0][st] = 0;
	q.push(Complex(0,st));
	while(!q.empty()) {
		Complex temp = q.top(); q.pop();
		int x = temp.pos,step = temp.step;
		v[step][x] = false;
		for(int i = _head[x];i;i = _next[i])
			if(step + lights[i] <=k && f[step + lights[i]][_aim[i]] > f[step][x] + _length[i]) {
				f[step + lights[i]][_aim[i]] = f[step][x] + _length[i];
				if(!v[step + lights[i]][_aim[i]]) {
					v[step + lights[i]][_aim[i]] = true;
					q.push(Complex(step + lights[i],_aim[i]));
				}
			}
	}
}




你可能感兴趣的:(图论,SPFA,bzoj,JLOI2014,分层图)