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


    题目大意:

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

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

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


    思路:

    昨天去B组划水时的T4。本来不想写B组的题解的,毕竟相对来说都很简单。但是最后一题既然是一道裸的分层图最短路,那就写一下吧。
    首先题目明显的指出了这是一道分层图最短路的题目。因为它要求第二种走法不超过kk次。
    然后我们需要判断两个点能否互相到达。由于n100nleq 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;
    }
    
  • 相关阅读:
    查看java代码,命令,ctrl+r
    JVM调优
    springboot线程池
    jpa
    复制java对象,jpa,save
    springboot添加切面
    gunicorn 实现 gevent 多线程
    经典算法
    python-生僻字转拼音
    HTML介绍
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998094.html
Copyright © 2020-2023  润新知