• bzoj 4398 福慧双修——二进制分组


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

    如果枚举1号点走哪些点出去,就从那些点出发跑多源最短路即可。最短路不会重复经过一条边。

    怎样枚举较优?需要枚举到答案的起点在一组、终点在另一组;考虑按点的编号二进制分组,即枚举每一位,为0的在一组,为1的在另一组。

    因为两个点编号不同,所以二进制表示至少有1位不同,即任意两个点一定一度被分到过两个组里。

    好像还有构造新图的更快的做法。不过也没管。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=4e4+5,M=1e5+5,K=20;
    int n,m,mx,hd[N],xnt=1,to[M<<1],nxt[M<<1],w[M<<1];
    int dis[N],sta[N],top,ans=1e9,bin[K];
    bool vis[N],use[M];
    priority_queue<pair<int,int> >q;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    void add(int x,int y,int z)
    {
      to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;
    }
    void init()
    {
      int k=n;while(k)k>>=1,mx++;mx--;
      bin[0]=1;for(int i=1;i<=mx;i++)bin[i]=bin[i-1]<<1;
    }
    void dj()
    {
      memset(vis,0,sizeof vis);
      while(q.size())
        {
          int k=q.top().second;q.pop();
          if(vis[k])continue;vis[k]=1;
          for(int i=hd[k],v;i;i=nxt[i])
        if(!use[i>>1]&&dis[v=to[i]]>dis[k]+w[i])
          {
            dis[v]=dis[k]+w[i];
            q.push(make_pair(-dis[v],v));
          }
        }
      ans=min(ans,dis[1]);
    }
    int main()
    {
      n=rdn(); m=rdn(); init();
      for(int i=1,u,v,z1,z2;i<=m;i++)
        {
          u=rdn();v=rdn();z1=rdn();z2=rdn();
          add(u,v,z1);add(v,u,z2);
        }
      for(int i=hd[1];i;i=nxt[i])sta[++top]=i;
      for(int i=0;i<=mx;i++)
        {
          memset(dis,0x3f,sizeof dis);
          for(int j=1;j<=top;j++)
        {
          int k=sta[j];
          if(!(to[k]&bin[i]))
            {
              q.push(make_pair(-w[k],to[k]));use[k>>1]=1;
              dis[to[k]]=w[k];
            }
        }
          dj();
          memset(dis,0x3f,sizeof dis);
          for(int j=1;j<=top;j++)
        {
          int k=sta[j];
          if(to[k]&bin[i])
            {
              q.push(make_pair(-w[k],to[k]));use[k>>1]=1;
              dis[to[k]]=w[k];
            }
          else use[k>>1]=0;
        }
          dj();
          for(int j=1;j<=top;j++)
        if(to[sta[j]]&bin[i])use[sta[j]>>1]=0;
        }
      printf("%d
    ",ans==1e9?-1:ans);
      return 0;
    }
  • 相关阅读:
    49. 字母异位词分组
    73. 矩阵置零
    Razor语法问题(foreach里面嵌套if)
    多线程问题
    Get json formatted string from web by sending HttpWebRequest and then deserialize it to get needed data
    How to execute tons of tasks parallelly with TPL method?
    How to sort the dictionary by the value field
    How to customize the console applicaton
    What is the difference for delete/truncate/drop
    How to call C/C++ sytle function from C# solution?
  • 原文地址:https://www.cnblogs.com/Narh/p/9795835.html
Copyright © 2020-2023  润新知