• POJ 2831 Can We Build This One?(最小生成树)


    题目链接:http://poj.org/problem?id=2831 

    题意: 

    题目大意:给张图,然后问你,如果某边的权值下降为V,那么这个边有无可能在最小生成树中呢?节点数≤1000,边数≤100000,询问数≤100000。

     思路:prim。

    考虑prim的算法过程:每次加入一个点,并且加入该点的条件是dis[i]是还没加入点的dis[]中最小的。

    所以执行prim时,用数组no[]保存某点加入的次序,numm[i]保存第i个加入的点的id

    查询边(a,b)时(假设a的加入次序先于b),则枚举no[a]+1 ~ no[b]加入的点的dis[],若存在x<=dis[k],原prim算法过程可被打破,边(a,b)会被选择,

    因为该边是当前最佳的边;否则还是原算法过程进行。 

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <iomanip>
     6 using namespace std;
     7 
     8 const int maxd = 1000001;
     9 const int N = 1005;
    10 const int M = 1000001;
    11 
    12 int map1[N][N], dis[N], vis[N], no[N], numm[N];
    13 struct Path
    14 {
    15     int a, b, c;
    16 }p[M];
    17 
    18 void prim(int n)
    19 {
    20     int cur;
    21     for(int i=1; i<=n; i++) dis[i] = maxd;
    22     memset(vis, 0sizeof(vis));
    23     cur = 1; dis[cur] = 0; vis[cur] = 1;
    24     no[cur] = 1; numm[1] = cur;
    25     //找n-1轮
    26     for(int i=2; i<=n; i++)
    27     {
    28         //枚举上一次加入的点与各个点的距离,更新最小距离dis[i]
    29         for(int j=1; j<=n; j++)
    30         {
    31             if(vis[j]==0 && dis[j]>map1[cur][j])
    32                 dis[j] = map1[cur][j];
    33         }
    34         //选出最短的边,把该边连接的点加入结果集
    35         int mind = maxd;
    36         for(int j=1; j<=n; j++)
    37         {
    38             if(vis[j]==0 && dis[j]<mind)
    39             {
    40                 mind = dis[j];
    41                 cur = j;
    42             }
    43         }
    44         vis[cur] = 1;
    45         no[cur] = i;
    46         numm[i] = cur;
    47     }
    48 }
    49 
    50 void init(int n)
    51 {
    52     for(int i=1; i<=n; i++)
    53         for(int j=1; j<=n; j++)
    54             map1[i][j] = maxd;
    55 }
    56 
    57 int main()
    58 {
    59     int n, m, q, pi, x;
    60     scanf("%d%d%d",&n, &m, &q);
    61     init(n);
    62     for(int i=1; i<=m; i++)
    63     {
    64         scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
    65         if(map1[p[i].a][p[i].b]>p[i].c)
    66             map1[p[i].a][p[i].b] = map1[p[i].b][p[i].a] = p[i].c;
    67     }
    68     //prim走一遍,保存no[],numm[],dis[]
    69     prim(n);
    70 
    71     for(int i=1; i<=q; i++)
    72     {
    73         scanf("%d%d",&pi,&x);
    74         int a = no[p[pi].a], b = no[p[pi].b], temp, flag = 0, bno, bnum, sno, snum;
    75         if(a>b){bno = a; bnum = p[pi].a; sno = b; snum = p[pi].b;}
    76         else {bno = b; bnum = p[pi].b; sno = a; snum = p[pi].a;}
    77         //枚举p[pi].a 和 p[pi].b两点之间加入的点
    78         //若x<=dis[],则该边为这轮的最优边,可成为最小生成树中的一边
    79         for(int k=sno+1; k<=bno; k++)
    80         {
    81             if(x<=dis[numm[k]])
    82             {
    83                 flag = 1;
    84                 break;
    85             }
    86         }
    87         if(flag==1)
    88             printf("Yes ");
    89         else
    90             printf("No ");
    91     }
    92     return 0;
    93 }
    View Code 
  • 相关阅读:
    MySql给表中某字段插入随机数
    MySql 基本语法_数据操作
    thinkphp中模板继承
    thinkphp中模块和操作映射
    如何让ThinkPHP的模板引擎达到最佳效率
    ThinkPHP访问不存在的模块跳到404页面
    thinkphp中I方法
    thinkphp中field方法
    thinkphp中F方法
    thinkphp中where方法
  • 原文地址:https://www.cnblogs.com/byluoluo/p/3454545.html
Copyright © 2020-2023  润新知