zoukankan      html  css  js  c++  java
  • 福慧双修&探险 BZOJ4398&BZOJ2407

    分析:

    双倍经验(数据范围不同)。

    我们考虑,我们必定是从1走一条边到节点i,之后从i到j跑最短路,之后再从j到1走另一条边的情况下,不会重复,并且是答案。那么我们考虑预处理出pre[i]表示从1走到i满足最短路的并且经过pre[i],pre[i]为路径第二个节点。那么,针对每一个边,(x,y,z,v)满足当x!=1&&y!=1时,如果pre[x]!=pre[y]连接1,x,dis[y]+z和1,y,dis[x]+v(因为答案如果经过这个边,那么答案一定是dis[x]+dis[y]+z或者dis[x]+dis[y]+v中的一个),如果pre[x]==pre[y],那么保留这两条边。需要特判x==1||y==1的情况,具体看代码。

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <vector>
    using namespace std;
    #define N 10010
    struct node
    {
    	int to,next,val;
    }e[600010];
    int dis[N],pre[N],vis[N],head[N],cnt,n,m;
    void add(int x,int y,int z)
    {
    	e[cnt].to=y;
    	e[cnt].next=head[x];
    	e[cnt].val=z;
    	head[x]=cnt++;
    }
    void spfa()
    {
    	queue <int>q;q.push(1);dis[1]=0;
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();vis[x]=0;
    		for(int i=head[x];i!=-1;i=e[i].next)
    		{
    			int to1=e[i].to;
    			if(dis[to1]>dis[x]+e[i].val)
    			{
    				dis[to1]=dis[x]+e[i].val;
    				pre[to1]=pre[x];
    				if(x==1)pre[to1]=to1;
    				if(!vis[to1])q.push(to1),vis[to1]=1;
    			}
    		}
    	}
    	//printf("%d %d %d
    ",dis[1],dis[2],dis[3]);
    }
    struct no
    {
    	int x,y,z,v;
    }a[400010];
    int main()
    {
    	//freopen("both.in","r",stdin);freopen("both.out","w",stdout);
    	memset(head,-1,sizeof(head));cnt=0;memset(dis,0x3f,sizeof(dis));
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].v);
    		add(a[i].x,a[i].y,a[i].z);add(a[i].y,a[i].x,a[i].v);
    	}
    	spfa();
    	memset(head,-1,sizeof(head));cnt=0;
    	for(int i=1;i<=m;i++)
    	{
    		int x=a[i].x,y=a[i].y,z=a[i].z,v=a[i].v;
    		if(x==1)
    		{
    			if(pre[y]!=y)add(1,y,z),dis[n+1]=min(dis[n+1],dis[y]+v);
    			else add(y,n+1,v);
    			continue;
    		}
    		if(y==1)
    		{
    			if(pre[x]!=x)add(1,x,v),dis[n+1]=min(dis[n+1],dis[x]+z);
    			else add(x,n+1,z);
    			continue;
    		}
    		if(pre[x]!=pre[y])add(1,y,dis[x]+z),add(1,x,dis[y]+v);
    		else add(x,y,z),add(y,x,v);
    	}
    	for(int i=1;i<=n;i++)dis[i]=1<<30;
    	spfa();
    	printf("%d
    ",dis[n+1]);
    	return 0;
    }
    

      

  • 相关阅读:
    IE8下提示'console'未定义错误
    左右添加和删除
    箭头函数
    事件冒泡
    选中状态改变,并且实现左边选中便便添加
    appcan里面模板的使用
    白面机器学习笔记(一)
    常见的模型加速方法
    相机的参数
    深度学习和机器学习的区别
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9107877.html
Copyright © 2011-2022 走看看