您的位置:首页 > 编程语言

NOIP2013模拟】DY引擎 题解+代码

2016-06-22 19:14 351 查看

Description

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)次。

Input

第一行有6个整数N,M,E,P,L,K分别代表:N个中转点,M个收费站,E条边,P个提示,DY引擎的有效距离L,DY引擎的使用次数K。

接下去E行,每行有3个整数u,v,w(1<=u, v<=N; 1<=w<=1,000,000)表示:u和v之间有一条长度为w的双向边。

接下去P行,每行有3个整数u,v,t(1<=u<=v<=N; 0<=t<=u-v+1)表示: [u, v] 标号区间至少有t个收费站。

Output

输出一个整数,表示小唐从PZU开到ZJU用的最短距离(瞬间转移距离当然是按0来计算的)。

Sample Input

6 2 6 2 5 1

1 2 1

2 3 2

3 6 3

1 4 1

4 5 2

5 6 3

2 5 2

4 6 2

Sample Output

1

【样例解释】

4、5是收费站。1->2(1)->6(1)

Data Constraint

对于30%的数据保证:

2<=N<=30,max(0, N-10) <=M<=N,0<=k<=10

对于100%的数据保证:

2<=N<=300,max(0, N-100) <=M<=N,E<=50,000,1<=P<=3,000,1<=L<=1,000,000,0<=K<=30

Solution

其实呢,这道题是由两道小题拼起来的。

1.对于一些约束,判断每个点是否为关键点

设s[i]表示1~i中收费站的数量,那么第i个点的状态即为s[i]-s[i-1]

那么它给出的条件([u, v] 标号区间至少有t个收费站)就是

s[v]−s[u−1]>=t

隐含条件

s[i]−s[i−1]>=0

s[i−1]−s[i]>=−1

那么按照查分约束那样,连边构图,从0开始求最长路即可。

详细可以点这里

单元最短路*1

2.在神奇条件的情况下求最短路

分为两步

首先,两个点如果能互相通过引擎飞过去,那么距离为0,预处理一下即可。N<=300那就Floyd做完。枚举k时注意判断k不是收费站

多元最短路*1

接着做最短路,单元最短路*2

搞定

Code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 1000
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int a[N][N],b[N][N],c[N][N],s[N],n,m,e,p,l,kk,next[500000],last[500000],to[500000],data[500000],dd[5000000],d[5000000][2],tot=0;
void putin(int x,int y,int z)
{
next[++tot]=last[x];last[x]=tot;to[tot]=y;data[tot]=z;
}

int main()
{
scanf("%d%d%d%d%d%d",&n,&m,&e,&p,&l,&kk);
fo(i,1,n) fo(j,1,n) a[i][j]=1000000000;
fo(i,1,e)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
z=min(z,a[x][y]);
c[x][y]=c[y][x]=a[x][y]=a[y][x]=z;
}
fo(i,1,p)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
putin(x-1,y,z);
}
fo(i,1,n) putin(i-1,i,0),putin(i,i-1,-1);
{
int i=0,j=1,bz
;dd[1]=0;
memset(s,128,sizeof(s));s[0]=0;memset(bz,0,sizeof(bz));bz[0]=1;
for(;i<j;)
{
int x=dd[++i];
for(int k=last[x];k;k=next[k])
{
if (s[to[k]]<s[x]+data[k])
{
s[to[k]]=s[x]+data[k];
if (bz[to[k]]==0)
{
dd[++j]=to[k];bz[to[k]]=1;
}
}
}
bz[x]=0;
}
}
for(int i=n;i;i--) s[i]=s[i]-s[i-1];
fo(k,1,n)
if (s[k]!=1)
{
fo(i,1,n)
if(i!=k)
fo(j,1,n)
if(i!=j && j!=k)
{
a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
//  if (a[i][j]<=l) b[i][j]=b[j][i]=1;
}
}
int f
[40],bz

;int i=0,j=1;
fo(i,1,n) if(b[1][i]==1) printf("%d\n",i);
d[1][0]=1;d[1][1]=0;memset(f,127,sizeof(f));memset(bz,0,sizeof(bz));f[1][0]=0;bz[1][0]=1;
for(;i<j;)
{
int x=d[++i][0];
fo(y,1,n)
{
if (c[x][y]>0 && f[y][d[i][1]]>f[x][d[i][1]]+c[x][y])
{
f[y][d[i][1]]=f[x][d[i][1]]+c[x][y];
if (bz[y][d[i][1]]==0)
{
d[++j][0]=y;d[j][1]=d[i][1];bz[y][d[i][1]]=1;
}
}
if (d[i][1]<kk && a[x][y]<=l && f[y][d[i][1]+1]>f[x][d[i][1]])
{
f[y][d[i][1]+1]=f[x][d[i][1]];
if (bz[y][d[i][1]+1]==0)
{
d[++j][0]=y;d[j][1]=d[i][1]+1;bz[y][d[j][1]]=1;
}
}
}
bz[x][d[i][1]]=0;
}
int ans=2147483647;
fo(i,0,kk) ans=min(ans,f
[i]);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: