• 生成树


      生成树

      即使是基础的算法也能出很难的题啊。

      先来一个板子题:

      [模板]最小生成树:https://www.luogu.org/problemnew/show/P3366

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <cstring>
     4 
     5 using namespace std;
     6 
     7 int G[5002][5002]={0},M[5002]={0};
     8 bool f[5002]={false};
     9 
    10 int main()
    11 {
    12     
    13     int n,m,x,y,z;
    14     memset(G,0x7f,sizeof(G));
    15     scanf("%d%d",&n,&m);
    16     for (int i=1;i<=m;i++)
    17     {
    18         scanf("%d%d%d",&x,&y,&z);
    19         if (G[x][y]>=z)
    20           G[x][y]=G[y][x]=z;
    21         }
    22     memset(M,0x7f,sizeof(M));    
    23     M[1]=0;
    24     memset(f,1,sizeof(f));
    25     for (int i=1;i<=n;i++)
    26     {
    27         int k=0;
    28         for (int j=1;j<=n;j++)
    29           if ((f[j]!=0)&&(M[j]<M[k])) k=j;
    30         f[k]=false;
    31         for (int j=1;j<=n;j++)
    32           if (f[j]&&M[j]>G[k][j])
    33             M[j]=G[k][j];
    34     }
    35     int A=0,S=0;
    36     for (int i=1;i<=n;i++)
    37       A+=f[i];
    38     if (A!=0) {printf("orz");
    39     return 0;}
    40     for (int i=1;i<=n;i++)
    41       S+=M[i];
    42     cout<<S;
    43     return 0;
    44  } 
    Prim
      
     1 // luogu-judger-enable-o2
     2 # include <cstdio>
     3 # include <iostream>
     4 # include <algorithm>
     5 # define R register int
     6 
     7 using namespace std;
     8 
     9 int fx,fy,n,m,ans,S;
    10 int F[5009];
    11 struct edge
    12 {
    13     int x,y,co;
    14 }g[200009];
    15 
    16 bool cmp(edge a,edge b)
    17 {
    18     return a.co<b.co;
    19 }
    20 
    21 int father(int x)
    22 {
    23     if(x!=F[x]) return F[x]=father(F[x]);
    24     return x;
    25 }
    26 
    27 int main()
    28 {
    29     scanf("%d%d",&n,&m);
    30     S=n;
    31     for (R i=1;i<=m;++i)
    32         scanf("%d%d%d",&g[i].x,&g[i].y,&g[i].co);
    33     sort(g+1,g+1+m,cmp);
    34     for (R i=1;i<=n;++i)
    35         F[i]=i;
    36     for (R i=1;i<=m;++i)
    37     {
    38         fx=father(g[i].x);
    39         fy=father(g[i].y);
    40         if(fx!=fy)
    41             F[fx]=fy,S--,ans+=g[i].co;
    42     }
    43     if(S!=1)
    44         printf("orz");
    45     else
    46         printf("%d",ans);
    47     return 0;
    48 }
    Kruskal

      $Prim$的时间复杂度:$O(V^{2})$

      $Kruskal$时间复杂度:$O(ElogE)$

      虽然$Kruskal$用的比较多,但是在处理近乎完全图的时候还是$Prim$比较快($E=V^{2}$)

      听说还有一种针对没有重复权值的图的算法:$Boruvka$,对于随机图来说$O(V+E)$,听起来还是很不错的,不过我觉得现在还没必要学这个。

      爱的供养:https://www.luogu.org/problemnew/show/P2266

      昨天做了NOI同步赛,赛后学了一种感觉很有用的Kruskal重构树,现在通过一道题来学习一下。

      归程:https://www.luogu.org/problemnew/show/P4768

      题意概述:给定一张无向图,每条边有长度和海拔,每次给定一个起点和水平面,要求开车走海拔高于水平面的边,再找一个地方下车走,最终到达1号,求走路这一部分的最小长度,强制在线。

      先从一号点跑$Dijkstra$求出每一个点到一号点的最短路,这一步是不可能省略的。现在考虑暴力,每次读入起点后跑BFS,可以得到50分。考虑离线,按照每次的水平面进行排序,把高于水平面的点进行合并(并查集),在同一个并查集中的点说明可以开车互相到达,这个并查集的权值就是这一些点里面离一号最近的点的权值。说的好,但是强制在线啊。可持久化并查集听说有卡过的,然而我不会。

      看看合并的顺序像不像一棵树呀。首先按照海拔排序,用kruskal的思路进行合并,每次将$f[u]$,$f[v]$连到一个新建的虚点上:点权为这条边的海拔,显然全部合并完后就会形成一棵树,这棵树就叫kruskal重构树。每次我们在这棵树上往上爬,当爬到最大的小于这次海平面的点时就说明如果海平面是这么大,这个点就只能合并到这里为止了。因为重构出的树的点权是单调的,可以树上倍增。如果学过这个算法的话这道题其实就是个模板,对于NOI选手应该是签到题?(听说这题卡SPFA)

      
      1 // luogu-judger-enable-o2
      2 # include <cstdio>
      3 # include <cstring>
      4 # include <iostream>
      5 # include <queue>
      6 # include <set>
      7 # include <algorithm>
      8 # define R register int
      9 
     10 inline int min (int a,int b) { if(a<b) return a; return b; }
     11 const int maxn=5e5+10;
     12 const int maxm=2e6+10;
     13 int cnt,T,n,m,h,da,k,s,fx,fy,u,v,l,a,p;
     14 int kh,firs[maxn<<1],F[maxn<<1][22],f[maxn<<1],val[maxn<<1];
     15 bool vis[maxn<<1];
     16 long long d[maxn<<1],ans=0,mind[maxn<<1];
     17 typedef std::pair <long long,int> pii;
     18 std::priority_queue <pii,std::vector<pii>,std::greater<pii> > q;
     19 int firs_k[maxm<<1];
     20 struct edge
     21 {
     22     int too,nex,l,a; //l长度,a海拔 
     23 }g[maxm<<1];
     24 struct lin
     25 {
     26     int x,y,a;
     27 }G[maxm];
     28 struct kru_tree
     29 {
     30     int nex,too;
     31 }kru[maxm<<1];
     32 
     33 inline void add (int x,int y,int l,int a)
     34 {
     35     g[++h].too=y;
     36     g[h].nex=firs[x];
     37     g[h].l=l;
     38     g[h].a=a;
     39     firs[x]=h;
     40 }
     41 
     42 inline void dij (int s)
     43 {
     44     memset(d,127,sizeof(d));
     45     memset(vis,0,sizeof(vis));
     46     d[s]=0;
     47     while (q.size()) q.pop();
     48     q.push(std::make_pair(d[s],s));
     49     int j,beg;
     50     while (q.size())
     51     {
     52         beg=q.top().second;
     53         q.pop();
     54         if(vis[beg]) continue;
     55         vis[beg]=true;
     56         for (R i=firs[beg];i;i=g[i].nex)
     57         {
     58             j=g[i].too;
     59             if(d[beg]+g[i].l>=d[j]) continue;
     60             d[j]=d[beg]+g[i].l;
     61             q.push(std::make_pair(d[j],j));
     62         }
     63     }
     64 }
     65 
     66 void add_edge(int x,int y)
     67 {
     68     kru[++kh].too=y;
     69     kru[kh].nex=firs_k[x];
     70     firs_k[x]=kh;
     71 }
     72 
     73 bool cmp (lin a,lin b)
     74 {
     75     return a.a>b.a;
     76 }
     77 
     78 int father (int x) { return f[x]?f[x]=father(f[x]):x; }
     79 
     80 void dfs (int x)
     81 {
     82     for (R i=firs_k[x];i;i=kru[i].nex)
     83         dfs(kru[i].too),mind[x]=min(mind[x],mind[ kru[i].too]),F[ kru[i].too ][0]=x;
     84     if(x<=n) mind[x]=d[x];
     85 }
     86 
     87 int main()
     88 {
     89     scanf("%d",&T);
     90     while (T--)
     91     {
     92         scanf("%d%d",&n,&m);
     93         ans=0,cnt=n,kh=0;
     94         memset(firs,0,sizeof(firs));
     95         memset(F,0,sizeof(F));
     96         memset(mind,127,sizeof(mind));
     97         memset(firs_k,0,sizeof(firs_k));
     98         memset(f,0,sizeof(f));
     99         memset(val,0,sizeof(val));
    100         h=0;
    101         for (R i=1;i<=m;++i)
    102         {
    103             scanf("%d%d%d%d",&u,&v,&l,&a);
    104             add(u,v,l,a);
    105             add(v,u,l,a);
    106             G[i].x=u;
    107             G[i].y=v;
    108             G[i].a=a;
    109         }
    110         dij(1);
    111         std::sort(G+1,G+1+m,cmp);
    112         for (R i=1;i<=m;++i)
    113         {
    114             fx=father(G[i].x);
    115             fy=father(G[i].y);
    116             if(fx==fy) continue;
    117             f[fx]=f[fy]=++cnt;
    118             add_edge(cnt,fx);
    119             add_edge(cnt,fy);
    120             val[cnt]=G[i].a;
    121         }
    122         dfs(cnt);
    123         scanf("%d%d%d",&da,&k,&s);
    124         for (int j=1;j<=21;++j)
    125             for (int i=1;i<=cnt;++i)
    126                 F[i][j]=F[ F[i][j-1] ][j-1];
    127         for (R i=1;i<=da;++i)
    128         {
    129             scanf("%d%d",&v,&p);
    130             v=(v+(long long)k*ans-1)%n+1;
    131             p=(p+(long long)k*ans)%(s+1);
    132             for (int j=21;j>=0;--j)
    133                 if(val[ F[v][j] ]>p) v=F[v][j];
    134             ans=mind[v];
    135             printf("%lld
    ",ans);
    136         }
    137     }
    138     return 0;
    139 }
    归程
  • 相关阅读:
    RadGrid Expand/Collapse on Row click
    AutoComplete Textbox with Additional Parameters From Database
    Combobox.Items中添加项Items
    JavaScript 处理字符串(操作字符串)
    用nettiers + svn + resharper + rad + ccNet开发前的准备工作
    Document.location.href和.replace的区别
    .net remoting的事务传播以及wcf分布式事务
    IDA反汇编/反编译静态分析iOS模拟器程序(三)函数表示与搜索函数
    [置顶] 一道有趣的逻辑题
    mini2440uboot移植基本操作指令
  • 原文地址:https://www.cnblogs.com/shzr/p/9239776.html
Copyright © 2020-2023  润新知