• 【bzo1579】拆点+dijkstra优先队列优化+其他优化


    题意:

    n个点,m条边,问从1走到n的最短路,其中有K次机会可以让一条路的权值变成0。
    1≤N≤10000;1≤M≤500000;1≤K≤20

    题解:

    拆点,一个点拆成K个,分别表示到了这个点时还有多少次机会。
    (x,k)-->(y,k-1),cost=0 或 (x,k)-->(y,k),cost=a[i].d;
    这题数据比较大, 需要很多优化。(应该只是蒟蒻我才需要这么多优化。。)
    1.不用spfa(时间复杂度不稳定),用dijkstra+优先队列优化
    2.拆点不拆边。g[i]表示i这个点是由谁拆分出来的,id[i]表示i这个点表示还能用几次,st[i]表示i拆分出来的点的编号从什么开始,图就按照原图建立,比如(x,k)-->(y,k-1)就可以直接找到st[x]+k -- > st[y]+k-1。
    3.如果“目标点n 用完了K次机会”这个状态到1的最短路已经算出来了,那一定是最优的,其它的都不用算了。加了这句话从10s+跑到了0.6s。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<vector>
      8 #include<cmath>
      9 using namespace std;
     10 
     11 typedef long long LL;
     12 const int N=2*20*10010,M=500010;//不知道为什么点要开两倍才能过。。。
     13 const LL INF=(LL)1e15;
     14 struct node{
     15     int x,y,next;
     16     LL d;
     17 }a[2*M];
     18 int n,m,K,len,num,first[N],g[N],id[N],st[N];
     19 LL dis[N],mn[N];
     20 struct point{int x;LL d;};
     21 struct cmp{
     22     bool operator () (point &x,point &y){return x.d>y.d;}
     23 };
     24 priority_queue<point,vector<point>,cmp> q;
     25 
     26 LL minn(LL x,LL y){return x<y ? x:y;}
     27 
     28 void ins(int x,int y,LL d)
     29 {
     30     a[++len].x=x;a[len].y=y;a[len].d=d;
     31     a[len].next=first[x];first[x]=len;
     32 }
     33 
     34 void dijkstra()
     35 {
     36     int y,bk=0;
     37     point t;
     38     for(int i=1;i<=num;i++) dis[i]=-1;
     39     // for(int i=1;i<=num;i++) if(dis[i]!=-1) printf("%d  g = %d  id = %d  dis = %lld
    ",i,g[i],id[i],dis[i]);
     40     
     41     memset(mn,127,sizeof(mn));
     42     while(!q.empty()) q.pop();
     43     for(int i=0;i<=K;i++) dis[st[1]+i]=0;
     44     
     45     for(int i=first[1];i;i=a[i].next)
     46     {
     47         for(int j=0;j<=K;j++)
     48         {
     49             t.x=st[a[i].y]+j;
     50             t.d=dis[st[1]+j]+a[i].d;
     51             if(mn[t.x]>t.d) mn[t.x]=t.d,q.push(t);//如果原来这个点已经可以被更优的所更新,那就不放到队列里面。
     52             if(j>=1)
     53             {
     54                 t.x=st[a[i].y]+j-1;
     55                 t.d=dis[st[1]+j];
     56                 if(mn[t.x]>t.d) mn[t.x]=t.d,q.push(t);
     57             }
     58         }
     59     }
     60     while(!q.empty() && !bk)
     61     {
     62         while(!q.empty())
     63         {
     64             t=q.top();q.pop();
     65             if(dis[t.x]==-1)
     66             {
     67                 dis[t.x]=t.d;
     68                 y=t.x;
     69                 if(y==st[n]) bk=1;
     70                 //如果“目标点n 用完了K次机会”这个状态到1的最短路已经算出来了,那一定是最优的,其它的都不用算了。加了这句话从10s+跑到了0.6s。
     71                 break;
     72             }
     73         }
     74         for(int i=first[g[y]];i;i=a[i].next)
     75         {
     76             t.x=st[a[i].y]+id[y];
     77             t.d=dis[y]+a[i].d;
     78             if(dis[t.x]==-1 && mn[t.x]>t.d) mn[t.x]=t.d,q.push(t);
     79             if(id[y]>=1)
     80             {
     81                 t.x=st[a[i].y]+id[y]-1;
     82                 t.d=dis[y];
     83                 if(dis[t.x]==-1 && mn[t.x]>t.d) mn[t.x]=t.d,q.push(t);
     84             }
     85         }
     86     }
     87 }
     88 
     89 int main()
     90 {
     91     // freopen("a.in","r",stdin);
     92     freopen("revamp.in","r",stdin);
     93     freopen("revamp.out","w",stdout);
     94     scanf("%d%d%d",&n,&m,&K);
     95     len=0;num=0;
     96     memset(first,0,sizeof(first));
     97     for(int i=1;i<=m;i++)
     98     {
     99         int x,y;LL d;
    100         scanf("%d%d%lld",&x,&y,&d);
    101         ins(x,y,d);
    102         ins(y,x,d);
    103     }
    104     for(int i=1;i<=n;i++)
    105         for(int j=0;j<=K;j++) 
    106         {
    107             g[++num]=i,id[num]=j;
    108             if(j==0) st[i]=num;
    109         }
    110     
    111     dijkstra();
    112     // for(int i=1;i<=num;i++) if(dis[i]!=-1) printf("%d  g = %d  id = %d  dis = %lld
    ",i,g[i],id[i],dis[i]);
    113     LL ans=INF;
    114     for(int i=st[n];i<=st[n]+K;i++) 
    115         if(dis[i]!=-1) ans=minn(ans,dis[i]);
    116     printf("%lld
    ",ans);
    117     return 0;
    118 }
  • 相关阅读:
    MM1排队系统
    java基本概念
    将博客搬至CSDN
    数据库知识点1
    离散分布
    概率论1--基本概念
    一道经典JS题(关于this)
    ajax请求过程中下载文件在火狐下的兼容问题
    熟悉css/css3颜色属性
    打字机游戏Ⅱ之手速pk
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5994631.html
Copyright © 2020-2023  润新知