zoukankan      html  css  js  c++  java
  • bzoj 4398 福慧双修 —— 二进制分组+多起点最短路

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4398

    按二进制每一位是 0/1 把 1 号点的儿子分成两组,分别作为起点和终点跑多起点最短路,最优解的起点和终点总有一次会被分到不同组里;

    太久没写 dijkstra 竟然WA了4次...别忘了 priority_queue 是大根堆-_-,还要注意循环计数的 i,j 不要重了...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int const xn=40005,xm=1e5+5,inf=0x3f3f3f3f;
    int n,m,hd[xn],ct,nxt[xm<<1],to[xm<<1],w[xm<<1],dis[xn],ans;
    bool vis[xn],in[xn],out[xn];
    struct N{
      int d,id;
      bool operator < (const N &y) const
      {return d>y.d;}//>
    };
    priority_queue<N>q;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
    void dij()
    {
      memset(vis,0,sizeof vis);
      while(q.size())
        {
          int x=q.top().id; q.pop();
          if(vis[x])continue; vis[x]=1;
          for(int i=hd[x],u;i;i=nxt[i])
        {
          if(vis[u=to[i]]||(u==1&&out[x])||(x==1&&in[u]))continue;
          if(dis[u]>dis[x]+w[i])
            dis[u]=dis[x]+w[i],q.push((N){dis[u],u});
        }
        }
      ans=min(ans,dis[1]);
    }
    int main()
    {
      n=rd(); m=rd();
      for(int i=1,x,y,z,k;i<=m;i++)
        {
          x=rd(); y=rd(); z=rd(); k=rd();
          add(x,y,z); add(y,x,k);
        }
      int cnt=0,t=n; while(t)cnt++,t/=2; ans=inf;
      for(int i=0;i<cnt;i++)
        {
          memset(dis,0x3f,sizeof dis); while(q.size())q.pop();
          for(int j=hd[1],u;j;j=nxt[j])
        {
          in[u=to[j]]=0; out[u]=0;
          if(u&(1<<i))dis[u]=w[j],out[u]=1,q.push((N){w[j],u});
          else in[u]=1;
        }      
          dij(); 
          memset(dis,0x3f,sizeof dis); while(q.size())q.pop();
          for(int j=hd[1],u;j;j=nxt[j])
        {
          if(in[u=to[j]])in[u]=0,out[u]=1,dis[u]=w[j],q.push((N){w[j],u});
          else out[u]=0,in[u]=1;
        }
          dij(); 
        }
      printf("%d
    ",(ans==inf?-1:ans));
      return 0;
    }
  • 相关阅读:
    设计模式之结构型外观模式
    设计模式之结构型装饰者模式
    设计模式之结构型组合模式
    设计模式之创建型建造者模式
    设计模式之创建型原型模式
    设计模式之创建型单例模式
    设计模式之创建型抽象工厂模式
    设计模式之创建型工厂模式
    设计模式之创建型简单工厂模式
    找出数组出现最多的元素,并返回出现的下标
  • 原文地址:https://www.cnblogs.com/Zinn/p/9801811.html
Copyright © 2011-2022 走看看