Cod sursa(job #167586)

Utilizator kaesarioDumi Loghin kaesario Data 29 martie 2008 20:19:13
Problema Salvare Scor 10
Compilator c Status done
Runda Arhiva de probleme Marime 5.55 kb
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INF 100001

typedef struct nod
{
	int x;
	struct nod * urm;
}TNod, *TLista;

int transf(FILE *f, TLista *v, int *g, int n, int m){
	/* transforma datele de intrere ale problemei "Salavre" in cele ale problemei "Cabane" */
	TLista nc;
	int i,j,k;
	for (i=0;i<n;i++){
		g[i]=0;
		v[i]=NULL;
	}
	for (k=0; k<n-1; k++){
		fscanf(f, "%i %i", &i, &j);
		i--;
		j--;
		g[i]++;
		g[j]++;
		nc = (TLista)malloc(sizeof(TNod));
		if (!nc)
			return -1;
		nc->x = j;
		nc->urm = v[i];
		v[i]=nc;
		
		nc = (TLista)malloc(sizeof(TNod));
		if (!nc)
			return -1;
		nc->x = i;
		nc->urm=v[j];
		v[j]=nc;
	}
	fclose(f);
	return 0;
}

int alege(int dm, int n, int m, TLista *v, int *gg, char *s){
	/* Functie ce se bazeaza pe algoritm de tip GREEDY 
	 * Se incearca amplasarea unui nr. de posturi de prim ajutor (<=m)
	 * care sa se afle la distanta maxima dm fata de frunze 
	 */
	int i, k, p, u, nr;
	int *g, *q, *d;
	char *w;
	TLista nc;
	/* g - grade noduri
	 * q - coada noduri
	 * p - primul din coada (elementul de prelucrat)
	 * u - ultimul din coada (marimea cozii)
	 * w - ne spune statutul nodurilor (vizitate sa nu)
	 * dm - distanta de la frunza la punct de prim ajutor
	 */
	/* alocari */
	g = (int *)malloc(n*sizeof(int));
	if (!g){
		printf("Eroare alocare!\n");
		return -2;
	}
	d = (int *)malloc(n*sizeof(int));
	if (!d){
		free(g);
		printf("Eroare alocare!\n");
		return -2;
	}
	q = (int *)malloc(n*sizeof(int));
	if (!q){
		free(d);
		free(g);
		printf("Eroare alocare!\n");
		return -2;
	}
	w = (char *)malloc(n);
	if (!q){
		free(d);
		free(g);
		free(q);
		printf("Eroare alocare!\n");
		return -2;
	}
	
	/* se creaza o copie a gradurilor nodurilor */
	memcpy(g, gg, n*sizeof(int));
	/* se initializeaza distantele de la frunze la puncte cu o valoare f. mare */
	for (i=0; i<n; i++){
		d[i] = INF;
		w[i] = 0;
	}
	/* se introduc frunzele in coada si se actualizeaza distanta lor cu dm */
	p = 0;
	u = -1;
	for (i=0; i<n; i++)
		if (g[i]==1){
			u++;
			q[u] = i;
			d[i] = dm;
			w[i] = 1;	// bagat in coada
		}
	/* se introduc restul de noduri in coada => u<n */
	nr = 0;
	while (u<n-1){
		/* se va prelua elementul curent si se vor scade gradele vecinilor */
		k = q[p];
		p++;
		nc = v[k];	// lista vecini
		while (nc!=NULL){
			if (!w[nc->x]){ // daca nu e bagat deja
				i = nc->x;
				break;
			}
			else
				nc=nc->urm;
		}
		/* scad grad */
		g[k]--;
		g[i]--;
		/* se actualizeaza distantele */
		if (d[k]<d[i])
			d[i]=d[k];
		/* se poate introduce in coada ? */
		if (g[i]==1){
			/* actualizez distanta */
			if (d[i]>0) d[i]--;
			/* poate fi punct de prim ajutor ? */
			if (d[i]==0){
				/* am gasit punct de prim ajutor =>
				 * il numaram si il marcam 
				 */
				nr ++;
				s[i]=1;
			}
			u++;
			q[u]=i;
			w[i] = 1;
		}
	}
	/* eliberari memorie */
	free(g);
	free(d);
	free(q);
	free(w);
	return nr;
}
int main(){
	/* variabile */
	int n, m, i, dmin, dmax, dmed, nr;
	int *g;
	char *s;
	FILE *f;
	char fin[15] = "salvare.in", fout[15] = "salvare.out";
	TLista *v, np, nc;
	/* n - nr. cabane
	 * m - nr. puncte prim ajutor ce trebuie deschise
	 * v - lista vecini pt. ficare nod
	 * g - vector grade noduri
	 * s - noduri selectate pt. puncte prim ajutor
	 */
	
	/* citire date - deschidere fisier*/
	f = fopen(fin, "rt");
	if (!f){
		printf("Eroare fisier intrare!\n");
		return -1;
	}
	fscanf(f, "%i %i", &n, &m);
	
	/* alocari */
	v = (TLista *)malloc(n*sizeof(TLista));
	if (!v){
		printf("Eroare alocare!\n");
		return -2;
	}
	g = (int *)malloc(n*sizeof(int));
	if (!g){
		free(v);
		printf("Eroare alocare!\n");
		return -2;
	}
	s = (char *)malloc(n);
	if (!s){
		free(v);
		free(g);
		printf("Eroare alocare!\n");
		return -2;
	}
	/* initial nu avem nicio cabana selectata pt. post de prim ajutor */
	for(i=0;i<n;i++)
		s[i]=0;
	/* ======= citire pt Salvare ==== */
	if (transf(f, v, g, n, m)){
		printf("Eroare transformare date!\n");
	}
	/* citire date */
	/*
	for (i=0; i<n; i++){
		s [i] = 0;//nu e marcat
		fscanf(f, "%i", g+i);
		v[i] = NULL; //initial
		for (j=0; j<g[i]; j++){
			nc = (TLista)malloc(sizeof(TNod));
			if (!nc){
				printf("Eroare alocare!\n");
				return -3;
			}
			fscanf(f,"%i", &(nc->x));
			nc->x--;	//adaptare notatie
			nc->urm = NULL;
			if (j==0){
				np = nc;
				v[i] = nc;
			}
			else{
				np->urm = nc;
				np = nc;
			}
		}
	}
	fclose(f);
	*/
	/* verificare citire 
	for (i=0; i<n; i++){
		np = v[i];
		while(np!=NULL){
			printf("%i ", np->x);
			np = np->urm;
		}
		printf("g=%i \n",g[i]);
	}
	*/
	
	/* === Algoritm ===*/
	/* Se aplica o cautare binara dupa dmed => O(lgn)*/
	dmin = 1; 
	dmax = n; 
	/*
	while(dmin<=dmax){ 
		dmed=(dmin+dmax)/2;
		nr = alege(dmed, n, m, v, g, s);
		if (nr<=m) 
			dmax=dmed-1; 
		else 
			dmin=dmed+1; 
	}
	*/
	/* === Varianta iterativa de cautare O(n) */
	
	for (dmed=1; dmed<=n; dmed++){
		for(i=0;i<n;i++) s[i]=0;
		nr = alege(dmed, n, m, v, g, s);
		if (nr<=m)
			break;
	}
	/* completare solutie */
	
	i=0;
	while(nr<m){
		if (s[i]!=1){
			s[i]=1;
			nr++;
		}
		i++;
	}
	
	/* afisare date */
	f = fopen(fout, "wt");
	fprintf(f, "%i\n", dmed);
	for (i=0; i<n; i++){
		if (s[i])
			fprintf(f, "%i ", i+1);
	}
	fprintf(f,"\n");
	fclose(f);
	/* eliberare memorie */
	for (i=0; i<n; i++){
		np = v[i];
		while (np!=NULL){
			nc = np;
			np = np->urm;
			free(nc);
		}
	}
	free(v);
	free(g);
	free(s);
	return 0;
}