zoukankan      html  css  js  c++  java
  • 题解 [NOI2014]魔法森林

    这题看起来一大堆 LCT 的题解,那我就来发一个动点 SPFA 的吧。

    SPFA 是啥不用我说了吧。

    动点SPFA

    这是一个动态加边的算法。

    我们现在假设图中已经有了一些边,从源点(v0)的最短路为(d_1,d_2,d_3,dots,d_n)

    我们考虑加一条边((u,v,d)),表示从(u)(v)的一条边,长度为(d)

    这时我们发现我们只要把(u,v)插入队列中跑一边 SPFA 就行了。

    想一想,为什么。

    因为我们只是添加了这一条边,别的边的最短路都处理好了。所以如果我们要更新最短路,一定要经过这条边。这下明白了把?

    同时由于之前处理过了。所以时间复杂度也会大大降低。

    不过由于总会有毒瘤出题人卡 SPFA 所以有别的算法时最好别用

    Solution

    这题的题解我们首先看到最大值最小会想到二分,但是因为边没有双单调性,所以这样做不具有正确性。

    那么我们可以将所有的边按(a_i)排序,枚举(i),动态加边,动点 SPFA ,求出从(1)开始经过的(b)边权最大值的最小值,这个就是三角不等式变个形,具体见代码。

    然后当前经过的a边权的最大值就是(a_i),不然的话就是没经过这条边,和上一次的答案时一样的。

    最后取一下最小值就可以了。

    代码

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    #define re register
    #define N 401001
    #define MAX 2001
    #define inf 1e18
    #define eps 1e-10
    using namespace std;
    typedef long long ll;
    typedef double db;
    inline void read(re ll &ret)
    {
        ret=0;re ll pd=0;re char c=getchar();
        while(!isdigit(c)){pd|=c=='-';c=getchar();}
        while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();}
        ret=pd?-ret:ret;
        return;
    }
    ll n,m,a,b,x,y,head[N],ans=inf,tot;
    ll d[N];
    struct edge
    {
    	ll from,to,x,y,nxt;
    	inline friend bool operator <(re edge a,re edge b)
    	{
    		return a.x<b.x;
    	}
    }e[N],f[N];
    inline void add(re ll u,re ll v,re ll dx,re ll dy)
    {
    	e[++tot].from=u;
    	e[tot].to=v;
    	e[tot].x=dx;
    	e[tot].y=dy;
    	e[tot].nxt=head[u];
    	head[u]=tot;
    	return;
    }
    queue<ll>q;
    bool vis[N];
    signed main()
    {
    	read(n);
    	read(m);
    	for(re int i=1;i<=m;i++)
    	{
    		read(f[i].from);
    		read(f[i].to);
    		read(f[i].x);
    		read(f[i].y);
    	}
    	sort(f+1,f+m+1);
    	for(re int i=1;i<=n;i++)
    		d[i]=inf;
    	d[1]=0;
    	for(re int i=1;i<=m;i++)
    	{
    		add(f[i].from,f[i].to,f[i].x,f[i].y);
    		add(f[i].to,f[i].from,f[i].x,f[i].y);
    		q.push(f[i].from);
    		q.push(f[i].to);
    		vis[f[i].from]=vis[f[i].to]=true;
    		while(!q.empty())
    		{
    			re ll ver=q.front();
    			q.pop();
    			vis[ver]=false;
    			for(re int j=head[ver];j;j=e[j].nxt)
    			{
    				re ll to=e[j].to,dis=e[j].y;
    				if(d[to]>max(d[ver],dis))
    				{
    					d[to]=max(d[ver],dis);
    					if(!vis[to])
    					{
    						vis[to]=true;
    						q.push(to);
    					}
    				}
    			}
    		}
    		ans=min(ans,d[n]+f[i].x);
    	}
    	if(ans==inf)
    		puts("-1");
    	else
    		printf("%lld
    ",ans);
    	exit(0);
    }
    
  • 相关阅读:
    http://kb.cnblogs.com/zt/ef/
    MVC3.0 上传图片并生成缩略图
    简单的js验证码
    KindEditor得不到textarea值的解决方法
    ffmpeg.exe dos下怎么用 放在哪里
    checkbox页面全选
    项目代码风格要求
    缓存
    上传文件大小的问题:超过了最大请求长度
    仿赶集网二手物品页面左侧导航
  • 原文地址:https://www.cnblogs.com/CelticBlog/p/13531585.html
Copyright © 2011-2022 走看看