LOJ#6075. 「2017 山东一轮集训 Day6」重建

题目描述:

  给定一个 n个点m 条边的带权无向连通图 ,以及一个大小为k 的关键点集合S 。有个人要从点s走到点t,现在可以对所有边加上一个非负整数a,问最大的a,使得加上a后,满足:s到t的最短路长度=s到t且只能经过S中的点的最短路长度。

题目分析:

  暴力

  记x为只经过关键点的最短路长度,其路径条数为n

  记y为可经过任意点的最短路长度,其路径条数为m

   tip:路径条数意思这里指 覆盖最短路的边数

  显然全部加上a之后最短路是不变的

  也就是说我们要求这个东西

$$a*n+x=a*m+y$$

$$a=(\frac{y-x}{n-m})_{max}$$

  所以我们怎么求这个东西呢

  当然是D(bao)P(li)咯

  假设f[i,j],g[i,j]表示到达i这个点,走过了j条边的最短路径

  其中f[i,j]只经过关键点,g[i,j]经过任意一点,这两个数组暴力DP就能求出来

  然后取出最大的a就好了

  关于无解的情况:上面那个式子的值<0显然是不行的,m=n显然是取任意的(当然实现的话就不用这样了判断,这样讲只是方便理解)

  代码:

  

 1 //许多大佬貌似喜欢在代码上面写自己id,那我这个蒟蒻也就从此开始——跟啦! 
 2 //好吧Koko不是重点 
 3 //LevenKoko 
 4 #pragma GCC optimize("Ofast")
 5 #include<bits/stdc++.h>
 6 #define int long long
 7 const int inf=1e18;
 8 using namespace std;
 9 inline int read(){
10     int ans=0,f=1;char chr=getchar();
11     while(!isdigit(chr)){if(chr=='-')f=-1;chr=getchar();}
12     while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
13     return ans*f;
14 }const int M=1e4+5,N=1e3+5;
15 int n,m,s,t,ans;
16 int head[N],nxt[M<<1],ver[M<<1],val[M<<1],tot,f[N][N],g[N][N],a[M],k;
17 inline void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],val[tot]=z,head[x]=tot;}
18 inline void Clear_All(){
19     memset(head,0,sizeof(head));
20     memset(a,0,sizeof(a));
21     for(int i=1;i<=n;i++)for(int j=0;j<=n;j++)f[i][j]=g[i][j]=inf;
22     tot=f[s][0]=g[s][0]=0;ans=-1;
23 }
24 inline void cmin(int &x,int y){return (void)(x=(x>y)?y:x);}
25 inline void cmax(int &x,int y){return (void)(x=(x>y)?x:y);}
26 inline void DP1(){
27     for(int i=0;i<n;i++)
28         for(int j=1;j<=n;j++)
29             if(f[j][i]<inf&&a[j])
30                 for(int k=head[j];k;k=nxt[k])
31                     cmin(f[ver[k]][i+1],f[j][i]+val[k]);    
32 }
33 inline void DP2(){
34     for(int i=0;i<n;i++)
35         for(int j=1;j<=n;j++)
36             if(g[j][i]<inf)
37                 for(int k=head[j];k;k=nxt[k])
38                     cmin(g[ver[k]][i+1],g[j][i]+val[k]);    
39 }
40 inline void Check_Get(){
41         for(int i=1;i<=n;i++){
42             if(f[t][i]==inf) continue;
43             int j;
44             for(j=1;j<=i;j++) 
45                 if(g[t][j]<f[t][i]) break;
46             if(j<=i) continue;
47             for(j=1;j<i;j++) if(g[t][j]!=inf) break;
48             if(j>=i){
49                 ans=inf; break;
50             }
51             int cur=inf;
52             for(j=1;j<i;j++)
53                 cur=min(cur,(-f[t][i]+g[t][j])/(i-j));
54             for(j=i+1;j<=n;j++)
55                 if(f[t][i]+i*cur>g[t][j]+j*cur) break;
56             if(j<=n) continue;
57             ans=max(ans,cur);
58         }
59 }
60 signed main(){
61 //    freopen("ernd.in","r",stdin);
62 //    freopen("ernd.out","w",stdout);
63     int T=read();
64     while(T--){
65         n=read(),m=read(),s=read(),t=read();Clear_All();
66         for(int i=1,x,y,z;i<=m;i++)x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
67         k=read();
68         for(int i=1,x;i<=k;i++) x=read(),a[x]=1;
69         DP1();DP2();
70         Check_Get();
71         if(ans==-1){puts("Impossible");continue;}
72         if(ans==inf){puts("Infinity");continue;}
73         printf("%lld\n",ans);
74     }
75     return 0;
76 }

 

 

 

posted @ 2019-07-13 14:54  zheng_liwen  阅读(394)  评论(0编辑  收藏  举报
/*去广告*/