zoukankan      html  css  js  c++  java
  • 【例题收藏】◇例题·II◇ Berland and the Shortest Paths

    ◇例题·II◇ Berland and the Shortest Paths

    题目来源:Codeforce 1005F +传送门+


    ◆ 简单题意

    给定一个n个点、m条边的无向图。保证图是连通的,且m≥n-1。

    以首都(1节点)为根节点生成最小树。树的值定义为每个节点的深度和(根节点深度0)。举个例子:

    而我们知道,可能有多种情况使树的权值最小,题目给出了一个整数k,如果最小树的生成方案数为ans,当 ans≤k 时,将 ans 种方案全部输出;当 ans>k 时,任意输出 k 种不同生成方案即可。输出方案格式为一个01串,第i个字符如果为0,表示不选第i条边(按照输入顺序),1为选择第i条边。


    ◆ 解析

    其实点 i 的深度 dep[i] 就是根节点1到 i 的路径,而我们知道 1 到 i 没有任何一条路径短于它们的最短路径,所以生成树的权值最小时,根节点到每个点的距离就是原图中根节点到每个节点的最短路径。也就是说,我们生成的最小树就是一个最短路径树。然而显然有时候存在多条最短路径,这也就造成了我们生成的最小树有多种解。于是我们假装生成一棵树,实际上只是生成一个图。

    由于这道题的边权都是等价的(不如就把边权看成1吧),我们可以用BFS直接求得最短路,所以说其实这也是一个BFS序图。为了考虑每种情况,我们把所有最小的BFS序边连上。下面再举一个生成BFS序图的例子(希望入门reader可以理解):

    这样我们就生成了一个BFS序有根图,由于我们要生成树,而树的每一个节点的父节点少于一个。在上图中,4的父节点有两个,因此需要断开一条边——两条边是等价的,断掉任意一条即可。

    我们可以把 u→v 的边存入v的边集 min_edg[v] ,那么最小权值树则是对于每一个除根节点之外的 v,选择 min_edg[v] 中的任意一条边,所以方案总数为 (除去根节点 i:2~n)min_edg[v]的边数之积。最后再DFS递归求方案即可(具体见代码)。


    ◆ 源代码

     1 /*Lucky_Glass*/
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<vector>
     6 #include<queue>
     7 using namespace std;
     8 const int MAXN=int(2e5);
     9 const int INF=int(1e9);
    10 int n_pnt,n_edg,k;
    11 int dis[MAXN+5];
    12 vector<pair<int,int> > lnk[MAXN+5];
    13 vector<pair<int,int> > min_edg[MAXN+5];
    14 void BFS(int start)
    15 {
    16     fill(dis,dis+MAXN+5,INF);
    17     dis[start]=0;
    18     queue<int> que;
    19     que.push(start);
    20     while(!que.empty())
    21     {
    22         int u=que.front();que.pop();
    23         for(int i=0;i<lnk[u].size();i++)
    24         {
    25             int v=lnk[u][i].first,id=lnk[u][i].second,Stp=dis[u]+1;
    26             if(Stp>dis[v]) continue;
    27             min_edg[v].push_back(make_pair(u,id));
    28             if(Stp!=dis[v])
    29                 dis[v]=Stp,que.push(v);
    30         }
    31     }
    32 }
    33 bool chose[MAXN+5];int cnt;
    34 void DFS(int v)
    35 {
    36     if(v==n_pnt+1)
    37     {
    38         cnt++;
    39         for(int i=1;i<=n_edg;i++)
    40             printf("%d",chose[i]);
    41         printf("
    ");
    42         return;
    43     }
    44     for(int i=0;i<min_edg[v].size();i++)
    45     {
    46         chose[min_edg[v][i].second]=true;
    47         DFS(v+1);
    48         chose[min_edg[v][i].second]=false;
    49         if(cnt==k) return;
    50     }
    51 }
    52 int main()
    53 {
    54     scanf("%d%d%d",&n_pnt,&n_edg,&k);
    55     for(int i=0,u,v;i<n_edg;i++)
    56         scanf("%d%d",&u,&v),
    57         lnk[u].push_back(make_pair(v,i+1)),
    58         lnk[v].push_back(make_pair(u,i+1));
    59     BFS(1);
    60     long long ans=1;
    61     for(int i=2;i<=n_pnt;i++)
    62     {
    63         ans*=min_edg[i].size();
    64         if(ans>k) break;
    65     }
    66     printf("%lld
    ",min(k*1ll,ans));
    67     DFS(2);
    68     return 0;
    69 }

    The End

    Thanks for reading!

    - Lucky_Glass

    (Tab:如果我有没讲清楚的地方可以直接在邮箱lucky_glass@foxmail.com email我,在周末我会尽量解答并完善博客~)

  • 相关阅读:
    [概述]移动机器人自主探索
    MRPT编译
    Kinect2.0相机标定
    小豆包的学习之旅:里程计运动模型
    小豆包的学习之旅:入门篇
    Kinect2.0点云数据获取
    COFF,amd64.vc90.mfc两个布署的问题
    [硬件]Robot运动控制
    [硬件]Urg_viewer数据读取
    [硬件]三维点云数据获取
  • 原文地址:https://www.cnblogs.com/LuckyGlass-blog/p/9338902.html
Copyright © 2011-2022 走看看