PAT顶级(思维+MST维护)——1013 Image Segmentation (35 分)

1013 Image Segmentation (35 分)


解题思路:

首先是:The dissimilarity D(C1,C2) of any two components C1 and C2 is larger than the confidence H of any of C1 and C2.这句话的意思是这句话不是D(C1,C2)>H(C1)&&D(C1,C2)>H(C2)而是D(C1,C2)>H(C1)||D(C1,C2)>H(C2),不然样例解释不通了。
然后我们可以思考,如果从零实现克鲁斯卡尔,这样的话对于当前寻找的边连着的点a,b,我们可以判断,假设a和b连起来之后是否能断开,即通过维护好的a,b集合的最小生成树的最大边以及元素个数直接判断, 如果能断开,就说明a和b不能加到一个集合的,如果不能,就将a和b加到一个集合并修护点的信息。可以这么想:即使你把他们连起来了,后续也一定会存在一个方法使得a和b断开。
通过这样的方法可以保证,在遍历已有边的所有情况下,能连起来的集合全部连起来了,保证了D(C1,C2)>H(C1)||D(C1,C2)>H(C2),也保证了而其他原本没有的边属于无穷大,显然满足上式。
至于维护信息的方法:
就在每次合并集合的时候将子集合的信息传递给父集合就好

代码:

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define G 6.67430*1e-11
#define  rd read()
#define pi 3.1415926535
using namespace std;
const ll mod = 1e9 + 7;
const int MAXN = 30000005;
const int MAX2 = 300005;
inline ll read() {
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch>'9') {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
#define int ll
struct ss
{
    int father;
    int num;
    int max;
}v[1005];

int find(int r) { return v[r].father == r ? r : v[r].father = find(v[r].father); }
int c;
void join(int x, int y, int value)
{
    int fx = find(x), fy = find(y);
    if (fx != fy)
    {
        ll C1 = v[fx].max * v[fx].num + c;
        ll C2 = v[fy].max * v[fy].num + c;
        if (value * v[fx].num <= C1 && value * v[fy].num <= C2)
        {
            v[fx].father = fy;
            v[fy].max = max({ v[fx].max, v[fy].max,value });
            v[fy].num += v[fx].num;
        }
    }
}
struct s
{
    int a, b, weight;
}e[1005];
bool cmp(s a, s b) { return a.weight < b.weight; }
bool cmp2(vector<int> a, vector<int> b) { return a[0] < b[0]; }
vector<int> ans[1005];
vector<vector<int>> a;
signed main()
{
    int n = rd, m = rd;
    c = rd;
    for (int i = 0; i < n; i++)
    {
        v[i].father = i;
        v[i].max = 0;
        v[i].num = 1;
    }
    for (int i = 0; i < m; i++)
    {
        e[i].a = rd;
        e[i].b = rd;
        e[i].weight = rd;
    }
    sort(e, e + m, cmp);
    for (int i = 0; i < m; i++)
    {
        join(e[i].a, e[i].b, e[i].weight);
    }
    for (int i = 0; i < n; i++)
    {
        ans[find(i)].push_back(i);
    }
    for (int i = 0; i < n; i++)
    {
        if (ans[i].size())a.push_back(ans[i]);
    }
    sort(a.begin(), a.end(), cmp2);
    for (int i = 0; i < a.size(); i++)
    {
        if (i)cout << endl;
        for (int j = 0; j < a[i].size(); j++)
        {
            if (j)cout << ' ';
            cout << a[i][j];
        }
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值