【BZOJ】1975: [Sdoi2010]魔法猪学院

题意

\(n(2 \le n \le 5000)\)个点,找尽量多的不同\(1\)\(n\)的路径,每一次的花费就是路径的全值和,要求在费用不超过\(E\)的情况下路径最多。

分析

裸的最段路。

题解

A*算法即可。

#include <bits/stdc++.h>
using namespace std;
typedef double lf;
const int N=5005, M=200005;
lf d[N], En;
typedef pair<lf, int> pr;
#define mkpr(x, y) make_pair<lf, int> (x, y)
priority_queue<pr, vector<pr>, greater<pr> >q;
struct Gr {
	struct E {
		int next, to;
		lf w;
	}e[M];
	int n, ihead[N], cnt;
	void add(int x, int y, lf w) {
		e[++cnt]=(E){ihead[x], y, w}; ihead[x]=cnt;
	}
	void dij() {
		static bool vis[N];
		memset(vis, 0, sizeof(bool)*(n+1));
		for(int i=1; i<=n; ++i) {
			d[i]=1e150;
		}
		d[n]=0;
		q.push(mkpr((lf)0, n));
		while(q.size()) {
			int x=q.top().second;
			q.pop();
			if(vis[x]) {
				continue;
			}
			vis[x]=1;
			for(int i=ihead[x]; i; i=e[i].next) {
				int y=e[i].to;
				if(d[y]>d[x]+e[i].w) {
					d[y]=d[x]+e[i].w;
					q.push(mkpr(d[y], y));
				}
			}
		}
	}
	int getans() {
		int ans=0;
		q.push(mkpr(d[1], 1));
		while(En>0 && q.size()) {
			int x=q.top().second;
			lf g=q.top().first-d[x];
			q.pop();
			if(x==n) {
				if(En>=g) {
					En-=g;
					++ans;
					continue;
				}
				else {
					break;
				}
			}
			for(int i=ihead[x]; i; i=e[i].next) {
				int y=e[i].to;
				lf w=e[i].w;
				// 有精度误差啊,不能乱减枝啊
				q.push(mkpr(g+w+d[y], y));
			}
		}
		return ans;
	}
}g, G;
int main() {
	int n, m;
	scanf("%d%d%lf", &n, &m, &En);
	g.n=G.n=n;
	for(int i=1; i<=m; ++i) {
		int x, y;
		lf e;
		scanf("%d%d%lf", &x, &y, &e);
		g.add(x, y, e);
		G.add(y, x, e);
	}
	G.dij();
	printf("%d\n", g.getans());
	return 0;
}
posted @ 2015-11-22 13:30  iwtwiioi  阅读(310)  评论(1编辑  收藏  举报