歌名 - 歌手
0:00

    【NOIP2013模拟】DY引擎

    题目

    BOSS送给小唐一辆车。小唐开着这辆车从PKU出发去ZJU上课了。
    众所周知,天朝公路的收费站超多的。经过观察地图,小唐发现从PKU出发到ZJU的所有路径只会有N(2<=N<=300)个不同的中转点,其中有M(max(0, N-100) <=M<=N)个点是天朝的收费站。N个中转点标号为1…N,其中1代表PKU,N代表ZJU。中转点之间总共有E(E<=50,000)条双向边连接。
    每个点还有一个附加属性,用0/1标记,0代表普通中转点,1代表收费站。当然,天朝的地图上面是不会直接告诉你第i个点是普通中转点还是收费站的。地图上有P(1<=P<=3,000)个提示,用[u, v, t]表示:[u, v]区间的所有中转点中,至少有t个收费站。数据保证由所有标记得到的每个点的属性是唯一的。
    车既然是BOSS送的,自然非比寻常了。车子使用了世界上最先进的DaxiaYayamao引擎,简称DY引擎。DY引擎可以让车子从U瞬间转移到V,只要U和V的距离不超过L(1<=L<=1,000,000),并且U和V之间不能有收费站(小唐良民一枚,所以要是经过收费站就会停下来交完钱再走)。
    DY引擎果然是好东西,但是可惜引擎最多只能用K(0<=K<=30)次。

    分析

    这道题的难点主要在求出哪个点有收费站。
    可以把题目分成两部分:

    求出哪个点有收费站

    这部分用到个很神奇的东西,差分约束系统
    \(s_{i}\)表示在中转点1~i有多少个收费站,
    那么对于每个提示[u,v,t],
    \(s_{v}-s_{u-1}>=c\),移项得\(s_{u-1}-s_{v}<=-c\)
    但这不足以求出所有的\(s\)值,那么注意隐藏条件:
    \(s_{i}-s_{i-1}>=0\),移项得\(s_{i-1}-s_{i}<=0\)
    \(s_{i}-s_{i-1}<=1\)
    接着对于一条式子“a-b<=c”,给b向a连一条权值为c的有向边,搞一遍spfa就可以了(其中\(s_{n}=m\),显然嘛)

    求最短路

    先把原图分为k+1层,
    搞一遍floyd,求出可以瞬移的路径,
    每一层连一条可以瞬移的路径到下一层。
    spfa完美收场。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const long long maxlongint=21474836470000;
    using namespace std;
    long long next[2000000],last[2000000],to[2000000],v[2000000],dis[2000000],d[5000000],f[400][400],re[60000][4];
    long long a[400][400];
    long long n,m,ans,k,l,e,tot;
    bool bz[2000000];
    long long bj(long long x,long long y,long long z)
    {
    	next[++tot]=last[x];
    	last[x]=tot;
    	to[tot]=y;
    	v[tot]=z;
    }
    long long spfa(long long x,long long y)
    {
    	memset(bz,true,sizeof(bz));
    	memset(dis,60,sizeof(dis));
    	long long head=0,tail=1,g;
    	dis[x]=y;
    	d[1]=x;
    	while(head<tail)
    	{
    		g=d[++head];
    		bz[g]=true;
    		for(long long i=last[g];i;i=next[i])
    		{
    			long long j=to[i];
    			if(dis[j]>dis[g]+v[i])
    			{
    				dis[j]=dis[g]+v[i];
    				if(bz[j])
    				{
    					bz[j]=false;
    					d[++tail]=j;
    				}
    			}
    		}
    	}
    }
    int main()
    {
    	//第一部分
    	long long o;
    	scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&e,&o,&l,&k);
    	memset(f,60,sizeof(f));
    	for(long long i=1;i<=e;i++)
    	{
    		long long x,y,z;
    		scanf("%lld%lld%lld",&x,&y,&z);
    		re[i][1]=x;
    		re[i][2]=y;
    		re[i][3]=z;
    		f[x][y]=min(z,f[x][y]);
    		f[y][x]=f[x][y];
    	}
    	for(long long i=1;i<=o;i++)
    	{
    		long long x,y,z;
    		scanf("%lld%lld%lld",&x,&y,&z);
    		bj(y,x-1,-z);
    	}
    	for(long long i=2;i<=n;i++)
    	{
    		bj(i,i-1,0);
    		bj(i-1,i,1);
    	}
    	spfa(n,m);
    	//第二部分
    	memset(last,0,sizeof(last));
    	tot=0;
    	for(long long i=1;i<=e;i++)
    	{
    		for(long long p=0;p<=k;p++)
    		{
    			bj(p*n+re[i][1],p*n+re[i][2],re[i][3]);
    			bj(p*n+re[i][2],p*n+re[i][1],re[i][3]);
    		}
    	}
    	for(long long i=1;i<=n;i++)
    		for(long long j=1;j<=n;j++)
    		{
    			for(long long p=1;p<=n;p++)
    				if(i!=j && j!=p && i!=p && dis[p]-dis[p-1]==0 && dis[p]<=m)
    				{
    					if(f[i][p]+f[p][j]<f[i][j])
    						f[i][j]=f[i][p]+f[p][j];
    				}
    			
    		}
    	for(long long i=1;i<=n;i++)
    		for(long long j=1;j<=n;j++)
    			if(i!=j && f[i][j]<=l)
    			{
    				for(long long p=0;p<=k-1;p++)
    				{
    					bj(p*n+i,(p+1)*n+j,0);
    				}
    			}
    	spfa(1,0);
    	ans=maxlongint;
    	for(long long i=0;i<=k;i++)
    		ans=min(dis[i*n+n],ans);
    	printf("%lld\n",ans);
    }
    
    
    
    posted @ 2018-05-12 19:52  无尽的蓝黄  阅读(300)  评论(0编辑  收藏  举报