zoukankan      html  css  js  c++  java
  • POJ 4046 Sightseeing 枚举+最短路 好题

    有n个节点的m条无向边的图,节点编号为1~n

    然后有点权和边权,给出q个询问,每一个询问给出2点u,v

    输出u,v的最短距离

    这里的最短距离规定为:

    u到v的路径的所有边权+u到v路径上最大的一个点权的和(点权也可以是u,v)

    n<=1000

    m<=20000

    Q<=20000

    时限:5000ms

    没有点权的话,好处理

    加了点权呢?

    我们可以先枚举n个节点,跑n次spfa,当枚举节点u时,我们默认节点u是所有路径上点权最大的一个点

    即我们枚举节点u时,我们先把点权比u大的节点删除了,在剩下的图跑spfa

    但实际上只要在spfa时加一句判断即可,并不用真的去重建图

    这样对于每一个询问,我们只要枚举点权最大的点就可以了,每一个询问是Q(n)

    ans=min(dis[i][u]+dis[i][v]+cost[i])

    但是这样我还是tle了, 因为这样需要开一个2维数组

    dis[i][j]表示以第i个点为起点,到达节点j的短路

    最后选择先存下所有询问,离线更新ans,在spfa的同时枚举更新

    为什么这样就可以了呢?

    因为一维数组比二维数组快很多。

    从这道题:

    1.当点权和边权混在一起比较难求的时候,我们可以先假设点权最大,分离出点权和边权,再枚举每一个点,就可以了

    不止这个, 枚举的思想在很多时候都很好用

    2.用stl的queue,时间是4000ms左右,用自己的队列,时间是3500左右,快了半秒

    3.一维数组的访问比二维数组快很多

    4.做题的时候要注意,循环的时候的终止条件,是到n? m? 还是Q?这个写错就wa了,又难发现

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 
      5 #define ll long long
      6 
      7 using namespace std;
      8 
      9 const int maxn=1005;
     10 const int maxm=20000+5;
     11 const ll inf=0x3f3f3f3f3f3f3f3f;
     12 
     13 struct Edge
     14 {
     15     int to,next;
     16     ll w;
     17 };
     18 Edge edge[maxm<<1];
     19 int head[maxn];
     20 int tot;
     21 int que[maxm<<2];
     22 ll ans[maxm];
     23 int a[maxm];
     24 int b[maxm];
     25 ll dis[maxn];
     26 ll cost[maxn];
     27 bool vis[maxn];
     28 int n,Q;
     29 
     30 void init()
     31 {
     32     memset(head,-1,sizeof head);
     33     tot=0;
     34 }
     35 
     36 void addedge(int u,int v,ll w)
     37 {
     38     edge[tot].to=v;
     39     edge[tot].w=w;
     40     edge[tot].next=head[u];
     41     head[u]=tot++;
     42 }
     43 
     44 void solve();
     45 
     46 int main()
     47 {
     48     int m;
     49     while(scanf("%d %d",&n,&m)){
     50         if(!n&&!m)
     51             break;
     52 
     53         for(int i=1;i<=n;i++)
     54             scanf("%lld",&cost[i]);
     55         int u,v;
     56         ll w;
     57         init();
     58         for(int i=1;i<=m;i++){
     59             scanf("%d %d %lld",&u,&v,&w);
     60             addedge(u,v,w);
     61             addedge(v,u,w);
     62         }
     63         scanf("%d",&Q);
     64         for(int i=1;i<=Q;i++){
     65             scanf("%d %d",&a[i],&b[i]);
     66         }
     67 
     68         solve();
     69     }
     70     return 0;
     71 }
     72 
     73 void spfa(int srt)
     74 {
     75     for(int i=1;i<=n;i++)
     76         dis[i]=inf;
     77     dis[srt]=0;
     78     memset(vis,false,sizeof vis);
     79     int l=0,r=0;
     80     que[r++]=srt;
     81     vis[srt]=true;
     82     while(l<r){
     83         int u=que[l++];
     84         vis[u]=false;
     85         for(int i=head[u];~i;i=edge[i].next){
     86             int v=edge[i].to;
     87             ll w=edge[i].w;
     88             if(cost[v]>cost[srt])
     89                 continue;
     90             if(dis[v]>dis[u]+w){
     91                 dis[v]=dis[u]+w;
     92                 if(!vis[v]){
     93                     que[r++]=v;
     94                     vis[v]=true;
     95                 }
     96             }
     97         }
     98     }
     99     for(int i=1;i<=Q;i++){
    100         if(dis[a[i]]==inf||dis[b[i]]==inf)
    101             continue;
    102         if(dis[a[i]]+dis[b[i]]+cost[srt]<ans[i])
    103             ans[i]=dis[a[i]]+dis[b[i]]+cost[srt];
    104     }
    105 }
    106 
    107 void solve()
    108 {
    109     for(int i=1;i<=Q;i++)
    110         ans[i]=inf;
    111     for(int i=1;i<=n;i++){
    112         spfa(i);
    113     }
    114 
    115     for(int i=1;i<=Q;i++){
    116         if(ans[i]==inf)
    117             printf("-1
    ");
    118         else
    119             printf("%lld
    ",ans[i]);
    120     }
    121     printf("
    ");
    122 
    123     return ;
    124 }
  • 相关阅读:
    Android实现简单的检测手机自由落体关闭屏幕
    Android Disable Package/Component 跳过app安装
    求单向链表中倒数第k个节点(c++):快慢指针/递归
    算法学习笔记---链表与数组
    pycharm使用matplotlib绘图学习笔记
    pycharm使用matplotlib绘制图像报错
    python numpy学习笔记
    python刷leetcode算法-- 左旋转字符串
    机器学习算法扫盲篇
    Kaggle入门篇
  • 原文地址:https://www.cnblogs.com/-maybe/p/4814954.html
Copyright © 2011-2022 走看看