1013 Image Segmentation (35分)(C++)

Image segmentation is usually formulated as a graph partition problem, where each segment corresponds to a connected component. Moreover, each pixel is the vertex of the graph. Each edge has a weight, which is a non-negative dissimilarity between neighboring pixels. So, the goal of image segmentation is to decompose the image graph into several disconnected components, where the elements in a component are similar and the elements in the different components are dissimilar.

The components are defined as follows:

  • A component is made of a set of connected vertices;
  • Any two components have no shared vertices;
  • The dissimilarity D(C1,C2) of any two components C1 and C2 is larger than the confidence H of any of C1 and C2.
  • The dissimilarity D(C1,C2) is defined to be the minimum edge weight of all the edges connecting C1 and C2, or infinity if no such edge exists;
  • The confidence of a component C, H(C), is defined to be the maximum edge weight of the minimum spanning tree of C, plus a function f(C)=c/∣C∣ where c is a positive constant and ∣C∣ is the size of the component C;
  • A set of vertices must not be treated as a component if they can be partitioned into two or more components.

Your job is to write a program to list all the components.

Input Specification:

Each input file contains one test case. For each case, the first line contains three integers: N​v​​ (0<N​v​​≤1000), the total number of vertices (and hence the vertices are numbered from 0 to N​v​​−1); N​e​​, the total number of edges; and c, the constant in the function f(C). Then N​e​​ lines follow, each gives an adge in the format:

V1 V2 Weight

Note: it is guaranteed that each pixel has no more than 8 neighboring pixels. The constant and all the weights are positive and are no more than 1000.

Output Specification:

For each case, list each component in a line. The vertices in a component must be printed in increasing order, separated by one space with no extra space at the beginning or the end of the line. The components must be listed in increasing order of their first vertex.

Sample Input 1:

10 21 100
0 1 10
0 3 60
0 4 90
1 2 90
1 3 50
1 4 200
1 5 86
2 4 95
2 5 5
3 4 95
3 6 15
3 7 101
4 5 500
4 6 100
4 7 101
4 8 101
5 7 300
5 8 50
6 7 90
7 8 84
7 9 34

Sample Output 1:

0 1 3 6
2 5 8
4
7 9

Sample Input 2:

7 7 100
0 1 10
1 2 61
2 3 50
3 4 200
4 5 82
5 0 200
3 6 90

Sample Output 2:

0 1
2 3 6
4 5

题目大意:给定常数c和一个图,包括Nv个点,Ne条边。现在要将每个图分割成几个小部分,要保证任意两个部分C1,C2满足D(C1, C2) > H(C1)或者D(C1,C2)>H(C2)。其中D(C1,C2)表示连接C1和C2两个部分的最短边(如果不存在为无穷大),H(C)表示C最小生成树中最大的边的weight + c/C的点的个数。

解题思路:最小生成树Kruskal算法(或者说并查集算法)

将Ne条边按照weight排序后进行遍历,假设现在遍历到e,对于e两个端点v1,v2所在的两个部分C1, C2而言,此时D(C1, C2)=e.weight,如果现在D(C1, C2) <= H(C1)并且D(C1,C2)<=H(C2),那我们就需要把这两个部分连接起来。连接的时候将原来两部分中较小的father节点作为新部分的father节点,并更新该father的H的值。

为了更新H值,我们另外需要两个矩阵cnt,maxWeight值,记录该节点所在component的节点数,以及最小生成树中的最大边的权重值。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
struct Edge{
	int v1, v2, weight;
	bool operator<(const Edge &a)const{
		return weight > a.weight;
	}
};
int father[maxn], maxWeight[maxn] = {}, cnt[maxn];
double H[maxn], c;
int Nv, Ne;
priority_queue<Edge> edges;
int findfather(int x){
	int a = x;
	while(x != father[x])
		x = father[x];
	while(a != x){
		int z = father[a];
		cnt[x] += cnt[a];
		cnt[a] = 0;
		maxWeight[x] = max(maxWeight[x], maxWeight[a]);
		father[a] = x;
		a = z;
	}
	return x;
}
void Union(Edge e){
	int faa = findfather(e.v1), fab = findfather(e.v2);
	if(faa > fab)
		swap(faa, fab);
	if(faa != fab && e.weight <= H[faa] && e.weight <= H[fab]){
		father[fab] = faa;
		cnt[faa] += cnt[fab];
		cnt[fab] = 0;
		maxWeight[faa] = max(maxWeight[faa], e.weight);
		H[faa] = maxWeight[faa] + c / cnt[faa];
	}
}
int main(){
	scanf("%d %d %lf", &Nv, &Ne, &c);
	for(int i = 0; i <  Nv; ++ i)
		father[i] = i;
	fill(H, H+Nv, c);
	fill(cnt, cnt+Nv, 1);
	Edge temp;
	for(int i = 0; i < Ne; ++ i){
		scanf("%d %d %d", &temp.v1, &temp.v2, &temp.weight);
		edges.push(temp);
	}
	while(!edges.empty()){
		temp = edges.top();
		edges.pop();
		Union(temp);
	}
	map<int, int> mp;
	int cnt = 0;
	for(int i = 0; i < Nv; ++ i){
		int fa = findfather(i);
		if(fa == i)
			mp[i] = cnt++;
	}
	vector<int> ans[cnt];
	for(int i = 0; i < Nv; ++ i)
		ans[mp[father[i]]].push_back(i);
	for(int i = 0; i < cnt; ++ i){
		printf("%d", ans[i][0]);
		for(int j = 1; j < ans[i].size(); ++ j)
			printf(" %d", ans[i][j]);
		printf("\n");
	}
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值