프로그래밍 알고리즘

[정올 2467] 비용

꾸준한사람 2023. 1. 8. 09:50
반응형

http://www.jungol.co.kr/bbs/board.php?bo_table=pbank&wr_id=1728&sca=99&sfl=wr_hit&stx=2467 

 

JUNGOL

 

www.jungol.co.kr

/*
비용
union find
가장 큰 비용을 가지는 w는, 해당 시작점 s와 끝점 e의 비용을 구할 때만 쓰이고 나머지 경로에서는 안 쓰인다.
즉 가장 큰 비용 w는 Cost(s,e) 딱 한 번에서만 쓰인다.
가장 큰 w가 쓰인다는 것은 Cost가 모든 w의 합이라는 뜻이다.
가장 큰 w를 쓰고 나면, 이제 w는 짤릴 일이 없으므로 w로 연결된 s, e를 하나의 점으로 여길 수 있다.
그렇다면, s,e가 아닌 점 a에 대해 Cost(a,s) == Cost(a,e)가 된다. 즉 각개격파가 되는 것이며 
따라서 합쳐진 그룹의 대표 Cost(a,s)만 구하고 s가 포함된 그룹의 개수만큼 곱해주면 여러 경우의 수를 한 번에 구할 수 있다.
*/
#include <stdio.h>

typedef long long LL;
const int LM = 100010;		//총 데이터 10만
const int MOD = (int)1e9;	//합이 10^9보다 크다면 나머지만 구해야 하므로

//G는 idx인 점이 어느 곳과 연결되어 있는지를 알려줌, cnt는 해당 점과 연결된 노드들의 수(하나로 봐야할 노드)
int N, M, G[LM], cnt[LM];
LL sum, ans; //현재 최대 비용과, 답(10^9의 나머지)
struct Data {
	int s, e, w; //시작점, 끝점, 그 사이의 비용
	//bool operator<(const Data&r)const {
	//	return w > r.w;
	//}
}A[LM], trr[LM];

bool comp(Data&a, Data&b) {
	return a.w > b.w;
}

void input() {
	scanf("%d %d", &N, &M);
	for (int i = 1; i <= M; ++i) {
		scanf("%d%d%d", &A[i].s, &A[i].e, &A[i].w);
		sum += A[i].w; //***현재 모든 구간이 없을 때의 총 비용을 미리 계산한다.
	}
	for (int i = 1; i <= N; ++i) {//초기화
		G[i] = i; //초기에 각 그룹은 자기 자신만 있는 단독그룹이다.
		cnt[i] = 1;//각 그룹의 점 수는 당연히 1
	}
}

void mergeSort(Data*arr, int s, int e) {
	if (s >= e) return;
	int m = (s + e) / 2, i = s, j = m + 1, k = s;
	mergeSort(arr, s, m);
	mergeSort(arr, m + 1, e);
	for (; k <= e; ++k) {
		if (i > m) trr[k] = arr[j++];
		else if (j > e) trr[k] = arr[i++];
		else if (comp(arr[i], arr[j]))
			trr[k] = arr[i++];
		//else if (arr[i]<arr[j]) trr[k] = arr[i++];
		else trr[k] = arr[j++];
	}
	for (i = s; i <= e; ++i) arr[i] = trr[i];
}

int Find(int r) {//점 r이 어느 그룹을 따르는지 리턴하고, 따르는 점들이 전부 root를 따르도록 수정
	return G[r] = r == G[r] ? r : Find(G[r]);
}
void unionFind() { //w로 정렬된 배열을 가지고 가장 큰 w부터 줄여가며 계산한다.
	for (int i = 1; i <= M; ++i) { //가장 큰 w로 연결된 s,e부터 내려간다.
		int s = Find(A[i].s), e = Find(A[i].e); //w로 연결된 s와 e의 그룹을 구함
		if (s != e) { //그룹이 다르면
			//현재 w가 현재기준 max값이므로, Cost(s,e)는 모든 w를 자른 비용이다.
			//s에 속한 그룹 노드중 하나 고르는 방법(sC1) * eC1(e에 속한 그룹) * 모든 w를 자른 비용
			ans = (ans + sum * cnt[s] % MOD*cnt[e]) % MOD;
			G[e] = s; //s와 e는 이제 같은 그룹
			cnt[s] += cnt[e]; //같은 그룹이 되었으므로 두 그룹의 점 개수 합침
		}
		sum -= A[i].w;//가장 큰 w를 전체w합에서 제거함
	}
}

int main() {
	//freopen("input.txt", "r", stdin);
	input();
	mergeSort(A, 1, M); //w의 크기에 따라 소팅한다.
	unionFind();
	printf("%lld\n", ans);
	return 0;
}
반응형

'프로그래밍 알고리즘' 카테고리의 다른 글

[정올 2497] 수열  (0) 2023.01.08
[정올 2468] 비밀번호  (0) 2023.01.08
[정올 2461] 공주님의 정원  (0) 2023.01.08
[정올 2300] 용액  (0) 2023.01.07
[정올 2261] 경로 찾기  (0) 2023.01.07