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\n");
        else
            printf("No\n");
    }

    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!\n");
 99             continue;
100         }
101         if (ans == smst(cost, n))printf("Not Unique!\n");
102         else printf("%d\n", 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 }

 

posted @ 2015-03-13 08:59  UsedRose  阅读(264)  评论(0编辑  收藏  举报