• 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
    ",ans);
    74     }
    75     return 0;
    76 }

     

     

  • 相关阅读:
    蓝桥杯 十六进制转八进制
    蓝桥杯 字母图形
    2017.12.13T19_B2_5mianshiti
    2017.11.21T19_B2_6.2讲义
    2017.12.13T19_B2_6zuoye
    2017.12.1T19_B2_5zuoye
    2017.12.1T19_B2_4zuoye
    2017.12.1T19_B2_4——2
    2017.12.1T19_B2_4.3kehouzuoye
    2017.12.1T19_B2_4.2
  • 原文地址:https://www.cnblogs.com/zhenglw/p/11180620.html
Copyright © 2020-2023  润新知