https://www.luogu.org/problemnew/show/P5122

题意:n个点,含有k个干草堆,问前n-1个点到第n个点的【经过任一干草堆的最短路】减去【不加限制的最短路】是否不超过那个干草堆的美味值。

思路:

①搞Dijkstra的变形,设d[i][0]为i到n的最短路,d[i][1]为i到n的经过干草堆的最短路减去那个干草堆的美味值的大小。松弛操作跟着变形。最后判断每个点是否d[i][1]<=d[i][0]

②加一个虚拟结点n+1,向k个干草堆连边,权值为每个干草堆到n的最短路减去美味值。跑两次Dijkstra即可。最后判断每个点是否d[i]<=d2[i]

无向图,直接从终点n往回跑就行了。

Q:为什么要把美味值加到边权里,不能最后判断每个点是否满足【经过干草堆的最短路】-美味值<=【不加限制的最短路】呢?

A:对于任一点i,如果最后判断,不知道【经过干草堆的最短路】经过的是哪个,也就不知道减的是哪个干草堆的美味值,而且,在Dijkstra处理中,对于这k个干草堆是不能一视同仁的,要综合考虑i经过每个干草堆到n的距离大小以及每个干草堆的美味值。故应该把美味值作为经过那个干草堆的路径的固有属性。

①:

#include<bits/stdc++.h>
using namespace std;
#define maxn 50000+1000
#define INF 0x3f3f3f3f

struct Edge{
	int from,to,dist;
};
struct HeapNode{
	int u,flag,d;
	bool operator < (const HeapNode& x)const{
		return d>x.d;
	}
};
int n,m,k,y[maxn];
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn][2];
int d[maxn][2];

void init()
{
	edges.clear();
	for(int i=1;i<=n;i++)G[i].clear();
}

void AddEdge(int f,int t,int d)
{
	edges.push_back((Edge){f,t,d});
	G[f].push_back(edges.size()-1);
}

void dijkstra(int s)
{
	priority_queue<HeapNode> Q;
	for(int i=1;i<=n;i++)d[i][0]=d[i][1]=INF;
	d[s][0]=0;
	memset(vis,0,sizeof(vis));
	Q.push((HeapNode){s,0,0});
	while(!Q.empty())
	{
		HeapNode x=Q.top();
		Q.pop();
		int u=x.u,flag=x.flag;
		if(vis[u][flag])continue;
		vis[u][flag]=1;
		for(int i=0;i<G[u].size();i++)
		{
			Edge& e=edges[G[u][i]];
			int v=e.to;
			if(!flag)
			{
				if(d[v][0]>d[u][0]+e.dist)
				{
					d[v][0]=d[u][0]+e.dist;
					Q.push((HeapNode){v,0,d[v][0]});
				}
				if(y[v]&&d[v][1]>d[u][0]+e.dist-y[v])
				{
					d[v][1]=d[u][0]+e.dist-y[v];
					Q.push((HeapNode){v,1,d[v][1]});
				}
			}
			else
			{
				if(d[v][1]>d[u][1]+e.dist)
				{
					d[v][1]=d[u][1]+e.dist;
					Q.push((HeapNode){v,1,d[v][1]});
				}
			}
		}
	}
}

int main()
{
//	freopen("input.in","r",stdin);
	scanf("%d%d%d",&n,&m,&k);
	int a,b,c;
	while(m--)
	{
		scanf("%d%d%d",&a,&b,&c);
		AddEdge(a,b,c);
		AddEdge(b,a,c);
	}
	for(int i=1;i<=k;i++)
	{
		scanf("%d%d",&a,&b);
		y[a]=b;
	}
	dijkstra(n);
	
	for(int i=1;i<n;i++)
		if(d[i][1]<=d[i][0])puts("1"); else puts("0");
	return 0;
}

②:

#include<bits/stdc++.h>
using namespace std;
#define maxn 50000+1000
#define INF 0x3f3f3f3f

struct Edge{
	int from,to,dist;
};
struct HeapNode{
	int u,d;
	bool operator < (const HeapNode& x)const{
		return d>x.d;
	}
};
int n,m,k,y[maxn];
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn],d2[maxn];

void init()
{
	edges.clear();
	for(int i=1;i<=n;i++)G[i].clear();
}

void AddEdge(int f,int t,int d)
{
	edges.push_back((Edge){f,t,d});
	G[f].push_back(edges.size()-1);
}

void dijkstra(int s,int *d)
{
	priority_queue<HeapNode> Q;
	for(int i=1;i<=n;i++)d[i]=d[i]=INF;
	d[s]=0;
	memset(vis,0,sizeof(vis));
	Q.push((HeapNode){s,0});
	while(!Q.empty())
	{
		HeapNode x=Q.top();
		Q.pop();
		int u=x.u;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<G[u].size();i++)
		{
			Edge& e=edges[G[u][i]];
			int v=e.to;		
			if(d[v]>d[u]+e.dist)
			{
				d[v]=d[u]+e.dist;
				Q.push((HeapNode){v,d[v]});
			}			
		}
	}
}

int main()
{
//	freopen("input.in","r",stdin);
	scanf("%d%d%d",&n,&m,&k);
	int a,b,c;
	while(m--)
	{
		scanf("%d%d%d",&a,&b,&c);
		AddEdge(a,b,c);
		AddEdge(b,a,c);
	}
	for(int i=1;i<=k;i++)
	{
		scanf("%d%d",&a,&b);
		y[a]=b;
	}
	dijkstra(n,d);
	for(int i=1;i<=n;i++)if(y[i])
	{
		AddEdge(n+1,i,d[i]-y[i]);
	}
	dijkstra(n+1,d2);
	for(int i=1;i<n;i++)
		if(d2[i]<=d[i])puts("1"); else puts("0");
	return 0;
}