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");
	}
}

 

發佈了465 篇原創文章 · 獲贊 91 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章