codeforces D.Dima and Bacteria (floyd+并查集)

题目链接:Dima and Bacteria

题意:

给出n个点,m条边,每条边是双向的,并且有权值。n个点分为k个种类,每个种类有Ci个点
如果任意两个相同点之间转移,可以找到一条路径,该路径满足经过的边的权值和为0则输出Yes,输出任意两个种类的点之间转移的最小路径。否则输出No;

思路:

分为两个问题
1.先用并查集判断是否相同种类任意两点是连通的。
对权值为0的边的顶点unite,然后查找每个种类的点是否都连通。
2.最短路问题
点不多,用floyd算法,解决最短路。d[i][j]=mi{d[i][j],d[i][k]+d[k][j]}

遇到的问题:

1.刚开始没想到可以用并查集解决第一个问题。
2.初始化越界了,找了好久。。。
3.floyd算法模板打错了。
4.并查集维护,应该对所有花费为0 的点都进行维护,刚开始就只对相同种类的点进行 维护。后来才发现错了。
第一次d题没去看题解解决了。但是写题半小时debug两小时。写题的时候细节没处理好,思维不够全面,一些细节总是想当然,一旦钻进牛角尖就很难出来了。

代码:

#include<iostream>
#include<vector>
#include<algorithm>
const int INF = 999999999;
using namespace std;
int c[610], d[510][510], type[101000], n, m, k, pre[101000];
//初始化
void init()
{
    int i, j;
    c[0] = 0;
    for (i = 1, j = 1; i <= k; ++i)
    {
        for (int l = 0; l<c[i]; ++l, ++j)
        {
            type[j] = i;
        }
    }
    for (i = 1; i <= k; ++i)
    {
        for (j = 1; j <=k; ++j)
        {
            if (i == j)d[i][j] = 0;
            else 
            d[i][j] = INF;
        }
    }
    for (i = 1; i <= n; ++i)
    {
        pre[i] = i;
    }
}
//并查集
int find(int x)
{
    if (pre[x] == x)
        return x;
    else
    {
        return pre[x] = find(pre[x]);
    }

}
void Unite(int x, int y)
{
    int fx = find(x), fy = find(y);
    if (fx != fy)pre[fy] = fx;
}

int main()
{
    int i, j;
    cin >> n >> m >> k;
    for (i = 1; i <= k; ++i)
        cin >> c[i];
    init();

    for (i = 0; i<m; ++i)
    {
        int s, t, p;
        cin >> s >> t >> p;
        if (type[s]!= type[t])
        {
            d[type[s]][type[t]] = min(p, d[type[s]][type[t]]);
            d[type[t]][type[s]] = min(p, d[type[t]][type[s]]);
        }
        //对边的权值为0 进行维护
        if (p == 0) {
            Unite(s, t);
        }
    }

    int flag = 0;
    //判断是否连通
    for (i = 1, j = 1; i <= k; ++i)
    {
        int f = find(j);
        for (int l = 0; l<c[i]; ++l, ++j)
        {
            if (find(j)!=f) {
                flag = 1;
                break;
            }
        }
        if (flag)break;
    }
    if (flag)
    {
        cout << "No" << endl;
    }
    else
    {
        cout << "Yes" << endl;
        //floyd算法找最短路
        for (i = 1; i <= k; ++i)
        {
            for (j = 1; j <= k; ++j)
            {
                for (int l = 1 ; l <= k; ++l)
                {
                    d[j][l] = min(d[j][l], d[j][i] + d[i][l]);
                }
            }
        }
        for (i = 1; i <= k; ++i)
        {
            for (j = 1; j <=k; ++j)
            {
                if (d[i][j] == INF)cout  << -1<<" ";
                else 
                cout <<d[i][j]<<" ";
            }
            cout << endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/PinappleMi/article/details/80290401
今日推荐