bzoj2156--星球探险

Description

众所周知,新世纪的科学很发达,于是Ray 和Raven 开始了星际探险,他们在宇宙中开辟了一片空间,建造了N 个空间站。这N 个空间站由一些单向的时空隧道连接,这些时空隧道都有一个穿越指数,穿过这些时空隧道,你可以走到未来或者回到过去,当然,这些都是由穿越指数决定的。有一天,Ray 和Raven 开始了一场比赛。他们要从一个空间站S 出发去另一个空间站T,先到的人获胜。Raven 一定会选一条能最快到达T 的路线。他希望Ray 输给他,所以事先在Ray 的飞船上设定了飞行路径,使得Ray 从S 到T 只能走一条特定的路径。但是,Ray 有对策,他有一台能够操纵时空隧道的机器,这台机器每次可以把某一条时空隧道的穿越指数增加或减少1,但是因为操纵机器很累,所以Ray 希望尽可能少改动,当然,如果改动后从某个空间站经过一系列的穿越可以在从这个空间站出发之前回到这个空间站,那么这样的改动是不允许的。修改之后,Raven 依然会走能最快到达终点的路线,所以Ray 是不可能赢的。但他请你帮助他确定改动时空隧道的方案,使得他能和Raven 同时到达T。

Input

输入的第一行包含两个整数N 和M,代表空间站的数目和时空隧道的数目。接下来M 行,每行三个整数u、v 和w,代表从空间站u 到空间站 v 有一条时空隧道,它的穿越指数是w。0 <= w <= 2000。空间站的编号是0 : : :N − 1。第M + 2 行包含一个整数p,代表Raven 在Ray 的飞船上设定的那条路径的空间站数。p <= N。第M + 3 行包含p 个互不相同的数,表示那条路径上的空间站的编号,第一个数是S,最后一个数是T。

Output

输出的第一行包含一个整数,表示Ray 走那条路径并且能够赢得比赛的情况下操纵时间机器的最小次数。

Sample Input

3 3
0 1 1
1 2 2
0 2 1
3
0 1 2

Sample Output

2

HINT

一共有10 个数据,对于第i (1 <= i <= 10) 个数据, N = i * 500, M = i * 5000。

题解:

  又是神题一枚qwq,哇这题居然没人发题解。

  题意就是给你一个有向图,每次你可以挑选其中任意的一条边,使其边权+1或者-1。现在给定你一条路径,求最少的操作,使给定的路径变为最短路。

  答案的下界是 给定路径与原图最短路的差。因为最多我们将给定路径或原图最短路,进行若干次操作,每一次操作只能将两者之间的差值缩短1个单位。

  另外,我们考虑dij或者spfa求最短路的过程。在每一次的松弛操作时,我们都需要判断是否dis[v]>dis[u]+e[i]].w,如果成立,就代表可以松弛,从而扔掉了原本的dis[v],更新为值较小的dis[u]+e[i].w。题中给了我们操作的权利,那我们何不将给定的路径,缩小到能够参与更新dis数组的程度呢。

  这样操作若干次以后,我们使得所有给定的路径,都能参与到更新dis数组,所以给定的路径已经被我们变成了一个新的最短路方案。

  由于以上的操作卡得很紧,所以最后我们只需要输出答案的下界,也就是给定路径和最短路的差即可。

  这题在bzoj上的样例输入被吞了一个回车,所以请注意p=3。

  1 #include<algorithm>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<queue>
  5 #include<cstdio>
  6 #include<cstring>
  7 using namespace std;
  8 const int maxn=10010;
  9 const int maxm=1000009;
 10 const int inf=0x3f3f3f3f;
 11 int tot=0,head[maxn],dis[maxn],num[maxn];
 12 bool vis[maxn];
 13 int n,m,ans=0;
 14 struct edge
 15 {
 16     int frm,to,nxt,w;
 17 }e[maxm];
 18 
 19 inline int read()
 20 {
 21     int x=0,f=1;char ch=getchar();
 22     while(ch<'0'||ch>'9')
 23     {if(ch=='_') f=-1;ch=getchar();}
 24     while(ch>='0'&&ch<='9')
 25     {x=x*10+ch-'0';ch=getchar();}
 26     return x*f;
 27 }
 28 
 29 void addedge(int u,int v,int w)
 30 {
 31     e[++tot].to=v;
 32     e[tot].frm=u;
 33     e[tot].w=w;
 34     e[tot].nxt=head[u];
 35     head[u]=tot;
 36 }
 37 
 38 void spfa(int s)
 39 {
 40     queue<int> q;
 41     for(int i=1;i<=n;i++)
 42         dis[i]=inf;
 43     dis[s]=0;
 44     q.push(s);
 45     vis[s]=1;
 46     while(!q.empty())
 47     {
 48         int u=q.front();
 49         q.pop();
 50         for(int i=head[u];i;i=e[i].nxt)
 51         {
 52             int v=e[i].to;
 53             if(dis[v]>dis[u]+e[i].w)
 54             {
 55                 dis[v]=dis[u]+e[i].w;
 56                 if(!vis[v])
 57                 {
 58                     q.push(v);
 59                     vis[v]=1;
 60                 }
 61             }
 62         }
 63         vis[u]=0;
 64     }
 65 }
 66 
 67 void get_len(int u,int v)
 68 {
 69     for(int i=head[u];i;i=e[i].nxt)
 70     {
 71         if(e[i].to==v)
 72         {
 73             ans+=e[i].w;
 74             return;
 75         }
 76     }
 77 }
 78 
 79 int main()
 80 {
 81     n=read();m=read();
 82     for(int i=1;i<=m;i++)
 83     {
 84         int a,b,c;
 85         cin>>a>>b>>c;
 86         addedge(a,b,c);
 87     }
 88     int p;
 89     p=read();
 90     for(int i=1;i<=p;i++)
 91     {
 92         num[i]=read();
 93     }
 94     int s=num[1],t=num[p];
 95     for(int i=1;i<p;i++)
 96     {
 97         get_len(num[i],num[i+1]);
 98     }
 99     spfa(s);
100     //cout<<dis[t]<<endl;
101     printf("%d",ans-dis[t]);
102     return 0;
103 }
104 /*
105 3 3
106 
107 0 1 1
108 
109 1 2 2
110 
111 0 2 1
112 
113 3
114 0 1 2
115 */
View Code

 

posted @ 2017-09-25 14:33  BK-Edwina  阅读(337)  评论(0编辑  收藏  举报