Cod sursa(job #168909)

Utilizator sanaDascalu Laurentiu sana Data 31 martie 2008 21:01:00
Problema Salvare Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.49 kb
#include <fstream>  
#include <vector>
#include <algorithm>
using namespace std;

#define FILEIN "salvare.in"  
#define FILEOUT "salvare.out"
#define INF 1000000

void dfs(int node, vector<vector <int> > &data, vector<int> &cost,
		vector<int> &taken, vector<int> used, vector<bool> &visited,
		vector<int> parent, int &dist, int &nr_pa, vector<int> &sol_part,
		int next);

void mysearch(vector<vector <int> > &data, vector<int> &cost,
		vector<int> &taken, vector<int> &used, vector<bool> &visited,
		vector<int> &parent, int &dist, int &nr_pa, vector<int> &sol_part);

void mysearch(vector<vector <int> > &data, vector<int> &cost,
		vector<int> &taken, vector<int> &used, vector<bool> &visited,
		vector<int> &parent, int &dist, int &nr_pa, vector<int> &sol_part) {
	nr_pa=0;
	for (int i=0; i<(int)used.size(); i++) {
		cost[i]=taken[i]=used[i]=parent[i]=0;
		visited[i]=false;
	}

	dfs(1, data, cost, taken, used, visited, parent, dist, nr_pa, sol_part, 0);

	if (cost[1]>dist) {
		sol_part[++nr_pa]=1;
		cost[1]=0;
	}
	int j=0;

	for (int i=nr_pa+1; i<(int)cost.size(); i++) {
		// Trec peste punctele deja amplasate.
		for (; cost[j]==0; j++)
			;
		sol_part[i]=j;
		cost[j]=0;
	}
}

void dfs(int node, vector<vector <int> > &data, vector<int> &cost,
		vector<int> &taken, vector<int> used, vector<bool> &visited,
		vector<int> parent, int &dist, int &nr_pa, vector<int> &sol_part,
		int next) {

	int gasit=0;
	used[node]=++next;

	for (int i=0; i<(int)data[node].size(); i++) {
		if (!used[data[node][i]]) {
			gasit=1;
			dfs(data[node][i], data, cost, taken, used, visited, parent, dist,
					nr_pa, sol_part, next);
			if ((cost[data[node][i]]+1)>cost[node]) {
				taken[node]=cost[node];
				cost[node]=cost[data[node][i]]+1;
				parent[node]=data[node][i];
			} else if ((cost[data[node][i]]+1)>taken[node]) {
				taken[node]=cost[data[node][i]]+1;
			}
			visited[node]=visited[node] | visited[data[node][i]];
		}
	}

	for (int i=0; i<(int)data[node].size(); i++) {
		if ((used[data[node][i]]>used[node]) && visited[data[node][i]]) {
			if (data[node][i]!=parent[node]) {
				if ( (cost[node]>cost[data[node][i]]+1) && ((cost[node]
						+cost[data[node][i]])<=2*dist))
					cost[node]=cost[data[node][i]]+1;
			} else if ((cost[node]>cost[data[node][i]]+1) && ((taken[node]
					+cost[data[node][i]])<=2*dist)) {
				cost[node]=cost[data[node][i]]+1;
			}
		}
	}

	if (!gasit)
		cost[node]=dist+1;

	if (cost[node]==2*dist+1) {
		cost[node]=0;
		visited[node]=true;
		sol_part[++nr_pa]=node;
	}
}

int main() {
	int N, K;
	int inf, sup, dist, nr_pa, dist_opt;
	vector<vector <int> > data;
	vector<int> used, cost, taken, parent;
	vector<int> sol;
	vector<int> sol_part;
	vector<bool> visited;
	ifstream fin(FILEIN,ios::in);
	ofstream fout(FILEOUT,ios::out);

	fin >> N >> K;
	for (int i=0; i<=N; i++) {
		data.push_back(vector<int>());
		visited.push_back(false);
		used.push_back(0);
		taken.push_back(0);
		cost.push_back(0);
		sol.push_back(0);
		sol_part.push_back(0);
		parent.push_back(0);
	}

	dist_opt=INF;

	for (int i=1; i<N; i++) {

		fin >> inf >> sup;
		data[inf].push_back(sup);
		data[sup].push_back(inf);
	}

	fin.close();
	/*	
	 for (int i=1;i<(int)data.size();i++) {
	 fout << i << " ";
	 for (int j=0;j<(int)data[i].size();j++) {
	 fout << data[i][j] << " ";
	 }
	 fout << endl;
	 }
	 */
	// Daca numarul de puncte de salvare este mai mare decat numarul de cabane
	// atunci infiintam in fiecare nod cate un punct de salvare.
	if (K>=N) {
		fout << 0 << endl;
		for (int i=1; i<=N; i++)
			fout << i << " ";
		fout.close();
		return 0;
	}

	// Evident ca numarul de puncte de ajutor este invers proportional
	// cu distanta minima ceruta. Cu cat crestem numarul de puncte de ajutor
	// cu atat distanta scade.

	inf=0;
	sup=N;
	dist=(inf+sup)/2;

	// Pentru o anumita distanta D calculez numarul de puncte de ajutor
	// necesare acoperirii arborelui.
	while (inf<=sup) {
		// Initial, numarul de puncte de ajutor este 0 si distanta o caut binar.
		dist=(inf+sup)/2;

		mysearch(data, cost, taken, used, visited, parent, dist, nr_pa,
				sol_part);

		// Daca numarul de puncte de ajutor este mai mare decat numarul limita
		// dat atunci distanta trebuie crescuta.
		if (nr_pa>K)
			inf=dist+1;
		else {
			sup=dist-1;
			if (dist_opt>dist) {
				for (int i=0; i<(int)sol_part.size(); i++)
					sol[i]=sol_part[i];
				dist_opt=dist;
			}
		}
	}

	fout << dist_opt << " " << nr_pa << endl;
	sort(sol.begin()+1, sol.begin()+nr_pa+1);
	for (int i=1; i<=nr_pa; i++)
		fout << sol[i] << " ";

	fout.close();
	return 0;
}

// Astfel se obtine o complexitate de O(N*logN).