zoukankan      html  css  js  c++  java
  • ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer <<LCA+tarjin离线+最小生成树(邻接表储存)

    题意

    在一个n*m的地图的线上造迷宫,给出每条边的造价,造出迷宫,使得地图上任两点有且仅有一条路,使迷宫造价最低,题目保证这样的迷宫唯一。建出迷宫之后有q次询问,询问两点间的距离。

    思路

    迷宫构造问题,起初没有思路,在一段思索之后和鸡神想出了反其道而行之的办法,先假设所有墙都有,我们要满足题设条件就要砸墙,每次砸最贵的墙,构成一颗生成树,所以就是建造这个迷宫就是求一个最大生成树的问题了,在此选用了kruskal算法。

    而后把这棵树存下来,然后就是想办法求树上任两点距离就行了,方法很多,但我和鸡神一种都不会,所以赛时我们就僵住了,最后我们考虑到q有10000次之大,所以我们跑了个离线算法(LCA+tarjin),当然此题RMQ,ST表好像都是可以跑的。

    关于tarjin+LCA之后放一道裸题详细分析,此题代码就不给注释了。

    代码

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef pair<int,int> PII;
      4 const int N=500+7;
      5 struct edge{
      6     int from,to,w;
      7 };
      8 struct askedge{
      9     int from,to,lca;
     10 }ae[N*N];
     11 edge mazee[N*N*4];
     12 int kfar[N*N];
     13 vector<int> G[N*N];
     14 vector<PII> pp[N*N];
     15 int tot=0;
     16 int n,m;
     17 void add_edge(int from,int to,int w)
     18 {
     19     mazee[tot].from=from;
     20     mazee[tot].to=to;
     21     mazee[tot].w=w;
     22     mazee[++tot].from=to;
     23     mazee[tot].to=from;
     24     mazee[tot].w=w;
     25 }
     26 void init()
     27 {
     28     for(int i=0;i<N*N;i++)
     29         kfar[i]=i;
     30 }
     31 bool cmp(edge a,edge b)
     32 {
     33     return a.w>b.w;
     34 }
     35 int Find(int x)
     36 {
     37     if(kfar[x]==x) return x;
     38     else return kfar[x]=Find(kfar[x]);
     39 }
     40 void Union(int x,int y)
     41 {
     42     x=Find(x);y=Find(y);
     43     if(x!=y) kfar[y]=x;
     44 }
     45 void kruskal()
     46 {
     47     sort(mazee,mazee+tot+1,cmp);
     48     int cnt=0;
     49     for(int i=0;i<n*m*4;i++)
     50     {
     51         edge &u=mazee[i];
     52         if(Find(u.from)!=Find(u.to))
     53         {
     54             Union(u.from,u.to);
     55             G[u.from].push_back(u.to);
     56             G[u.to].push_back(u.from);
     57             cnt++;
     58         }
     59         if(cnt==n*m-1) break;
     60     }
     61 }
     62 int far[N*N];
     63 int dist[N*N];
     64 int tarjinfind(int x)
     65 {
     66     if(far[x]==x) return x;
     67     else return far[x]=tarjinfind(far[x]);
     68 }
     69 void tarjinunion(int x,int y)
     70 {
     71     x=tarjinfind(x);y=tarjinfind(y);
     72     if(x!=y) far[y]=x;
     73 }
     74 void dfs(int now)
     75 {
     76     far[now]=now;
     77     for(int i=0;i<pp[now].size();i++)
     78     {
     79         PII &v=pp[now][i];
     80         if(dist[v.first]!=-1)
     81         {
     82             ae[v.second].lca=tarjinfind(v.first);
     83         }
     84     }
     85     for(int i=0;i<G[now].size();i++)
     86     {
     87         int &v=G[now][i];
     88         if(dist[v]==-1)
     89         {
     90             dist[v]=dist[now]+1;
     91             dfs(v);
     92             tarjinunion(now,v);
     93         }
     94     }
     95 }
     96 int main()
     97 {
     98     scanf("%d%d",&n,&m);
     99     for(int i=1;i<=n;i++)
    100     {
    101         for(int j=1;j<=m;j++)
    102         {
    103             char opd,opr;
    104             int down,right;
    105             scanf(" %c%d %c%d",&opd,&down,&opr,&right);
    106             if(opd!='X')
    107                 add_edge((i-1)*m+j,i*m+j,down);
    108             if(opr!='X')
    109                 add_edge((i-1)*m+j,(i-1)*m+j+1,right);
    110         }
    111     }
    112     init();
    113     kruskal();
    114     int q;
    115     scanf("%d",&q);
    116     for(int i=1;i<=q;i++)
    117     {
    118         int x1,y1,x2,y2;
    119         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    120         int u=m*(x1-1)+y1,v=m*(x2-1)+y2;
    121         pp[u].push_back(make_pair(v,i));
    122         pp[v].push_back(make_pair(u,i));
    123         ae[i]={u,v,-1};
    124     }
    125     memset(dist,-1,sizeof(dist));
    126     dist[1]=0;
    127     dfs(1);
    128     for(int i=1;i<=q;i++)
    129     {
    130         askedge &now=ae[i];
    131         printf("%d
    ",dist[now.from]+dist[now.to]-2*dist[now.lca]);
    132     }
    133     return 0;
    134 }

    后记

    赛时迅速的口A了这一题,奈何卡在求树上任两点距离,还算错了500*500,导致RE了十发。然后网上模板都是前向星,然而我不会,还是喜欢邻接表哎,所以赛后我自己改出了邻接表版本哈哈哈,希望以后能够继续多学习算法吧,口A码不出太难过了。向图论大师李老师致敬!

  • 相关阅读:
    Android应用性能测试
    Jmeter 中使用非GUI启动进行压力测试
    软件工程结对作业01
    第六周进度条
    求一维数组最大最大子数组和
    第五周进度条
    第四周进度条博客
    软件工程个人作业03
    第四周四则运算3 PSP表格
    poj 2096 概率dp
  • 原文地址:https://www.cnblogs.com/computer-luo/p/9622072.html
Copyright © 2011-2022 走看看