1. 程式人生 > >動態維護最小生成樹(IOI2003Maintain)

動態維護最小生成樹(IOI2003Maintain)

WOJ2235

Maintain

描述

農夫約翰的奶牛們希望能夠在農場的N(1<=N<=200)塊田地中自由的旅遊,儘管這些田地被樹林分開了。他們希望能夠通過維護一對對田地間的路徑使得任意兩塊田地間都有通路。奶牛們可以沿著任一方向的維護的路徑旅遊。

奶牛們並不建立路徑,取而代之,他們維護他們所發現的野生動物建立的路徑,任意一週,他們可以選擇維護任意的一個或所有的他們所知道的野生動物建立的路徑。

令人驚奇的是,奶牛們在每週周初總會發現一條新的野生動物建立的路徑。在這之後,他們必須在當週決定需要維護的那套路徑使得任意兩塊田地間都有通路。奶牛們只能維護目前所使用的路徑。    奶牛們總是希望減少他們必須維護的路徑的總長度。他們可以維護任意的子集,這個子集是他們已知的野生動物的路徑,這些路徑必須是他們上週維護的或是本週發現的。    野生動物的路徑不是直的。連線兩點可能有多條路徑,他們可能有不同的長度。兩條路徑可能相交,但奶牛們很牛,除非他們在一塊田地裡,他們拒絕改變路線。

輸入

輸入的第一行給出兩個正整數N和W,兩個數之間用空格分開,W是程式應執行的星期數(1 <= W <= 200)。

對於每個星期,讀入一行,這一行包含著當週被發現的野生動物建立的路徑,每一行包含著用空格分開的三個整數,路徑的兩個端點(田地的號碼)和該路徑的長度(1到10000的整數)。沒有任何路徑是以某地發出並以該地結束的。

輸出

在你的程式瞭解一條新的野生動物路徑後,你需要輸出一個數,這個數是奶牛們需要維護的滿足題目要求的路徑的總長度的最小值。如果沒有一套路徑能使得奶牛們可以在任意兩塊田地間通行的話,輸出-1。

你的程式應該在完成最後一週的任務後退出。

樣例輸入

4 6 1 2 10 1 3 8 3 2 3 1 4 3 1 3 6 2 1 2

樣例輸出

-1 -1 -1 14 12 8

題解

從小到大,插入排序。 每一次都加入一條新邊,做一下kruskal最小生成樹,刪去無用的邊,再輸出答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

struct edge{
	int u,v,w;
}e[20010];
int n,m,fa[20010],L=0;
edge s;

int find(int x){//查 
	if(x==fa[x])return x;
	return fa[x]=find(fa[x]);
}
int unionn(int x,int y){//並 
	fa[find(x)]=y;
}

int kruskal(int x){
	int ans=0,k=0;
	for(int i=1;i<=x;i++){
		if(find(e[i].v)!=find(e[i].u)){
			unionn(e[i].u,e[i].v);
			ans+=e[i].w;
			k++;
		}
		if(k==n-1)break;
	}
	if(k<n-1)return -1;
	return ans;
}

void Sort(){
	int i,j;
	for(i=L;i>=0;i--)
		if(e[i].w<=s.w)break;
	for(j=L;j>=i;j--)e[j+1]=e[j];
	e[i+1]=s;L++;
	//cout<<i<<" ";
}

int main(){
	scanf("%d%d",&n,&m);
	e[0].v=0;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&s.u,&s.v,&s.w);
		Sort();//cout<<e[1].w<<" "<<e[2].w<<" "<<e[3].w<<" "<<e[4].w;
		if(i<n-1){
			printf("-1\n");
			continue;
		}
		for(int j=1;j<=i;j++)fa[j]=j;
		printf("%d\n",kruskal(i));
	}
	return 0;
}