【JZOJ1782】Travel【分层图最短路】

题目大意:

题目链接:https://jzoj.net/senior/#main/show/1782
给出一个有nn个顶点mm条边的有向图,对于一条边长度为lenlen的边有两种走法。

  1. 如果aabb可以互达,则走过这条边的时间为lenlen
  2. 如果aabb不可以互达,则走过这条边的时间为2×len2\times len

现在给出一个kk,问,从顶点11到顶点nn,满足第二种走法不超过kk次的最短时间是多少。


思路:

昨天去B组划水时的T4。本来不想写B组的题解的,毕竟相对来说都很简单。但是最后一题既然是一道裸的分层图最短路,那就写一下吧。
首先题目明显的指出了这是一道分层图最短路的题目。因为它要求第二种走法不超过kk次。
然后我们需要判断两个点能否互相到达。由于n100n\leq 100,所以直接用FloydFloyd就可以了。
如果两个点x,yx,y可以互相到达,那么dis[x][y]dis[x][y]dis[y][x]dis[y][x]都应该小于\infty
然后就是一道裸的分层图最短路了。第一条道路在相同层之间建立,第二条道路在相邻层之间建立。


代码:

#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;

const int N1=110,N2=2010,M=500010,Inf=1e9;
int n,m,p,S,T,tot,X[M],Y[M],D[M],head[N2],dis1[N1][N1],dis2[N2];
bool vis[N2];

struct edge
{
	int next,to,dis;
}e[M];

void add(int from,int to,int dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

void floyd()
{
	for (int k=1;k<=n;k++)
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				if (i!=j && j!=k && k!=i && dis1[i][j]>dis1[i][k]+dis1[k][j])
					dis1[i][j]=dis1[i][k]+dis1[k][j];
}

void spfa()
{
	memset(dis2,0x3f3f3f3f,sizeof(dis2));
	queue<int> q;
	q.push(S);
	dis2[S]=0;
	vis[S]=1;
	while (q.size())
	{
		int u=q.front(),v;
		q.pop();
		vis[u]=0;
		for (int i=head[u];~i;i=e[i].next)
		{
			v=e[i].to;
			if (dis2[v]>dis2[u]+e[i].dis)
			{
				dis2[v]=dis2[u]+e[i].dis;
				if (!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
}

int main()
{
	memset(head,-1,sizeof(head));
	memset(dis1,0x3f3f3f3f,sizeof(dis1));
	scanf("%d%d%d",&n,&m,&p);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&X[i],&Y[i],&D[i]);
		dis1[X[i]][Y[i]]=D[i];
	}
	floyd();
	for (int i=1;i<=m;i++)
		if (dis1[X[i]][Y[i]]<Inf && dis1[Y[i]][X[i]]<Inf)
			for (int j=0;j<=p;j++) add(j*n+X[i],j*n+Y[i],D[i]);
		else
			for (int j=0;j<p;j++) add(j*n+X[i],j*n+n+Y[i],D[i]*2);
	S=1; T=N2-1;
	for (int i=0;i<=p;i++) add(i*n+n,T,0);
	spfa();
	if (dis2[T]<Inf) printf("%d",dis2[T]);
		else printf("-1");
	return 0;
}
posted @ 2019-07-10 08:00  全OI最菜  阅读(133)  评论(0编辑  收藏  举报