zoukankan      html  css  js  c++  java
  • nyoj 修路方案 (判断最小生成树是否唯一)

    1.

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    
    struct node
    {
        int x, y, dis;
        int flag;
        bool operator<(const node a) const {
            return dis < a.dis;
        }
    } a[200010];
    
    
    int fa[555], n;
    
    int kruskal(int num, int m)
    {
        int i, j, k;
        int ans = 0, cnt = 1;
        for (i = 0; i<m; i++)
        {
            if (i == num)//除去这条边之后再求一次最小生成树
                continue;
            int x = fa[a[i].x];
            int y = fa[a[i].y];
            if (x != y)
            {
                ans += a[i].dis;
                cnt++;
                fa[y] = x;
                for (j = 0; j <= n; j++)
                    if (fa[j] == y)
                        fa[j] = x;
            }
        }
        if (cnt != n)
            return -1;
        else
            return ans;
    }
    
    int main()
    {
        int m, i, j, t, sum, ans, cnt;
        scanf("%d", &t);
        while (t--)
        {
            scanf("%d%d", &n, &m);
            for (i = 0; i <= n; i++)
                fa[i] = i;
            for (i = 0; i<m; i++)
            {
                scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].dis);
                a[i].flag = 0;
            }
            sort(a, a + m);
            cnt = 1;
            ans = 0;
            for (int i = 0; i < m; ++i) {
                int x = fa[a[i].x];
                int y = fa[a[i].y];
                if (x != y) {
                    a[i].flag = 1;
                    ans += a[i].dis;
                    cnt++;
                    fa[y] = x;
                    for (int j = 0; j <= n; ++j)    //路径压缩
                        if (fa[j] == y)
                            fa[j] = x;
                }
            }
            int flag = 0;
            for (i = 0; i<m; i++)
            {
                if (a[i].flag == 0) continue;   //枚举去掉每一天最小生成树的边    
                for (int j = 0; j <= n; ++j)    //重新计算最小生成树
                    fa[j] = j;
                sum = kruskal(i, m);
                if (sum == ans) {                //判断是否唯一
                    flag = 1;
                    break;
                }
            }
            if (flag)
                printf("Yes
    ");
            else
                printf("No
    ");
        }
    
        return 0;
    }

    2.

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<string>
     6 #include<queue>
     7 #include<algorithm>
     8 #include<map>
     9 #include<iomanip>
    10 #include<climits>
    11 #include<string.h>
    12 #include<cmath>
    13 #include<stdlib.h>
    14 #include<vector>
    15 #define INF 1e7
    16 #define MAXN 100010
    17 #define maxn 555
    18 #define Mod 1000007
    19 #define N 1010
    20 #define MAX 0x0fffffff
    21 #define MIN -0x0fffffff
    22 using namespace std;
    23 typedef long long LL;
    24 
    25 int T;
    26 int G[maxn][maxn], maxlen[maxn][maxn],dis[maxn],pre[maxn];
    27 bool vis[maxn];
    28 int n, m;
    29 int u, v, w;
    30 int prim()
    31 {
    32     int min, pos;
    33     memset(vis, 0, sizeof(vis));
    34     for (int i = 1; i <= n; ++i) {
    35         dis[i] = G[1][i];
    36         pre[i] = 1;
    37     }
    38     vis[1] = 1;
    39     for (int i = 1; i < n; ++i) {
    40         min = MAX;
    41         for (int j = 1; j <= n; ++j) {
    42             if (!vis[j] && dis[j] < min) {
    43                 pos = j;
    44                 min = dis[j];
    45             }
    46         }
    47         int pr = pre[pos];
    48         maxlen[pos][pr] = maxlen[pr][pos] = G[pos][pr];
    49         for (int j = 1; j <= n; ++j)
    50             if (vis[j])
    51                 maxlen[j][pos] = maxlen[pos][j] = max(maxlen[j][pr], maxlen[pos][pr]);
    52         vis[pos] = 1;
    53         for (int j = 1; j <= n; ++j) {
    54             if (!vis[j] && dis[j] > G[j][pos]) {
    55                 dis[j] = G[j][pos];
    56                 pre[j] = pos;
    57             }
    58         }
    59     }
    60     for (int i = 1; i < n; ++i)
    61         for (int j = i + 1; j <= n; ++j) {
    62             if (pre[i] == j || pre[j] == i) continue;
    63             else if (maxlen[i][j] == G[i][j]) return 1;
    64         }
    65     return 0;
    66 }
    67 
    68 void process()
    69 {
    70     scanf("%d%d", &n, &m);
    71     for (int i = 0; i <= n; ++i)
    72         for (int j = 0; j <= n; ++j) {
    73             G[i][j] = MAX;
    74             maxlen[i][j] = MIN;
    75         }
    76         for (int j = 1; j <= m; ++j){
    77             scanf("%d%d%d", &u, &v, &w);
    78             G[u][v] = G[v][u] = w;
    79         }
    80     if (prim()) puts("Yes");
    81     else puts("No");
    82 }
    83 
    84 int main()
    85 {
    86     scanf("%d",&T);
    87     while (T--)
    88         process();
    89     return 0;
    90 }

     3.

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <algorithm>
      4 #include <string.h>
      5 using namespace std;
      6 
      7 /*
      8 * 次小生成树
      9 * 求最小生成树时,用数组Max[i][j]来表示MST中i到j最大边权
     10 * 求完后,直接枚举所有不在MST中的边,替换掉最大边权的边,更新答案
     11 * 点的编号从0开始
     12 */
     13 const int MAXN = 110;
     14 const int INF = 0x3f3f3f3f;
     15 bool vis[MAXN];
     16 int lowc[MAXN];
     17 int pre[MAXN];
     18 int Max[MAXN][MAXN];//Max[i][j]表示在最小生成树中从i到j的路径中的最大边权
     19 bool used[MAXN][MAXN];
     20 int Prim(int cost[][MAXN], int n)
     21 {
     22     int ans = 0;
     23     memset(vis, false, sizeof(vis));
     24     memset(Max, 0, sizeof(Max));
     25     memset(used, false, sizeof(used));
     26     vis[0] = true;
     27     pre[0] = -1;
     28     for (int i = 1; i<n; i++)
     29     {
     30         lowc[i] = cost[0][i];
     31         pre[i] = 0;
     32     }
     33     lowc[0] = 0;
     34     for (int i = 1; i<n; i++)
     35     {
     36         int minc = INF;
     37         int p = -1;
     38         for (int j = 0; j<n; j++)
     39             if (!vis[j] && minc>lowc[j])
     40             {
     41                 minc = lowc[j];
     42                 p = j;
     43             }
     44         if (minc == INF)return -1;
     45         ans += minc;
     46         vis[p] = true;
     47         used[p][pre[p]] = used[pre[p]][p] = true;
     48         for (int j = 0; j<n; j++)
     49         {
     50             if (vis[j])Max[j][p] = Max[p][j] = max(Max[j][pre[p]], lowc[p]);
     51             if (!vis[j] && lowc[j]>cost[p][j])
     52             {
     53                 lowc[j] = cost[p][j];
     54                 pre[j] = p;
     55             }
     56         }
     57     }
     58     return ans;
     59 }
     60 int ans;
     61 int smst(int cost[][MAXN], int n)
     62 {
     63     int Min = INF;
     64     for (int i = 0; i<n; i++)
     65         for (int j = i + 1; j<n; j++)
     66             if (cost[i][j] != INF && !used[i][j])
     67             {
     68                 Min = min(Min, ans + cost[i][j] - Max[i][j]);
     69             }
     70     if (Min == INF)return -1;//不存在
     71     return Min;
     72 }
     73 int cost[MAXN][MAXN];
     74 int main()
     75 {
     76     int T;
     77     int n, m;
     78     scanf("%d", &T);
     79     while (T--)
     80     {
     81         scanf("%d%d", &n, &m);
     82         int u, v, w;
     83         for (int i = 0; i<n; i++)
     84             for (int j = 0; j<n; j++)
     85             {
     86                 if (i == j)cost[i][j] = 0;
     87                 else cost[i][j] = INF;
     88             }
     89         while (m--)
     90         {
     91             scanf("%d%d%d", &u, &v, &w);
     92             u--; v--;
     93             cost[u][v] = cost[v][u] = w;
     94         }
     95         ans = Prim(cost, n);
     96         if (ans == -1)
     97         {
     98             printf("Not Unique!
    ");
     99             continue;
    100         }
    101         if (ans == smst(cost, n))printf("Not Unique!
    ");
    102         else printf("%d
    ", ans);
    103     }
    104     return 0;
    105 }
    kuangbin

    另外从网上看到的次小生成树。。 第一次接触

    转自http://blog.csdn.net/yhrun/article/details/6916489

    解题思路:花费最少且任意两个城市能够相同,则说明要求最小生成树。而题目中问是否存在另外一种方案,达到

    最小生成树的效果,所以可以采用次小生成树

    常用的一种方法就是在求出最小生成树的基础上进行添加边

    具体实现:先用prim算法求出最小生成树,并且统计任意一点到其他各点的路径上的最大边权。然后添加改生成树上没有的边(u,v),添加一条边后就会形成环,

    然后删除该环中权值第二大的边(即除(u,v)之外的最大权值的边),然后再次统计此时的的费用,如果和最小生生成树的费用相同,则说明存在另外一种方案。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 #include<cstdio>
     6 using namespace std;
     7 #define M 501
     8 int ch1[M][M];   //保存原始边
     9 int ch2[M][M];   //ch2[i][j]表示i到j的路径中的最大比边
    10 vector<int> s;   //保存最小生成树的节点
    11 int v[M];        //标记访问过的节点
    12 int sum=0;
    13 void prim(int m,int n)
    14 {
    15     s.clear();s.push_back(m);v[m]=1;
    16     while(s.size()!=n)
    17     {
    18         int k=200000,x,y;
    19         for(int i=0;i<s.size();i++)
    20         {
    21             int r=s[i];
    22             for(int j=1;j<=n;j++)
    23             {
    24                 if(!v[j]&&ch1[r][j]!=-1)
    25                 {
    26                     if(k>ch1[r][j])
    27                     {
    28                         k=ch1[r][j];x=r;y=j;
    29                     }
    30                 }
    31             }
    32         }
    33         for(int i=0;i<s.size();i++)
    34         {
    35             if(ch2[s[i]][x]<ch1[x][y])
    36             {ch2[y][s[i]]=ch2[s[i]][y]=ch1[x][y];}
    37             else {ch2[y][s[i]]=ch2[s[i]][y]=ch2[s[i]][x];}
    38         }
    39         s.push_back(y);sum+=k;v[y]=1;ch1[x][y]=-1;ch1[y][x]=-1;
    40     }
    41 }
    42 int main()
    43 {
    44     int N;scanf("%d",&N);
    45     while(N--)
    46     {
    47         int m,n;scanf("%d%d",&m,&n);
    48         memset(ch1,-1,sizeof(ch1));memset(ch2,-1,sizeof(ch2));memset(v,0,sizeof(v));
    49         for(int i=0;i<n;i++)
    50         {
    51             int x,y,z;scanf("%d%d%d",&x,&y,&z);
    52             ch1[x][y]=z;ch1[y][x]=z;
    53             ch2[x][y]=z;ch2[y][x]=z;
    54         }
    55         prim(1,m);int flat=0;
    56         for(int i=1;i<=m;i++)
    57         {
    58             for(int j=1;j<=m;j++)
    59             {
    60                 if(ch1[i][j]!=-1)
    61                 {
    62                     //cout<<i<<"   "<<j<<"   "<<ch1[i][j]<<endl;
    63                     //cout<<ch2[i][j]<<endl;
    64                     int k=sum-ch2[i][j]+ch1[i][j];
    65                     if(k==sum)
    66                     {
    67                         flat=1;break;
    68                     }
    69                 }
    70             }
    71             if(flat)break;
    72         }
    73         if(flat)cout<<"Yes"<<endl;
    74         else cout<<"No"<<endl;
    75     }
    76 }
  • 相关阅读:
    jedis scan实现keys功能
    java简单实现一个阻塞式线程池
    Swift运算符
    数组的使用(1)
    Linux 常用命令
    Task02:基础查询与排序
    Task01:初识数据库
    摩尔投票法
    面向对象暑期课程总结
    xpath+requests+peewee——CSDN论坛全方位爬虫
  • 原文地址:https://www.cnblogs.com/usedrosee/p/4334257.html
Copyright © 2011-2022 走看看