Cod sursa(job #373915)

Utilizator stocarulCosmin-Mihai Tutunaru stocarul Data 15 decembrie 2009 14:36:06
Problema Cuplaj maxim de cost minim Scor 50
Compilator c Status done
Runda Arhiva educationala Marime 3.82 kb
#include<stdio.h>
#define infile "cmcm.in"
#define outfile "cmcm.out"
#define nmax 737
#define mmax (100*1001)
#define inf ~(1<<31)
struct muchie
{
	int p,q,c; //muchia [p,q] de cost c
	char viz; //marcam daca avem muchia folosita
} m[mmax]; //muchiile
struct lista
{
	int n,c,m,p; //nodul, costul, muchia, respectiv pozitia urmatoare
} l[mmax], lt[mmax]; //lista grafului normal si a celui transpus
struct nod
{
	int p; //pozitia catre lista
} n[nmax],nt[nmax]; //informatiile nodurilor din graful normal si cel transpus
char viz[nmax]; //vizite pentru coada
int c[nmax]; //coada pentru bf
int x[nmax]; //costul minim cu care ating nodurile
int y[nmax]; //nodul din care am atins acest nod
int z[nmax]; //muchia cu care am atins acest nod
int nrm,nrl; //numarul de muchii respectiv numarul din lista
int a,b; //numarul de noduri din cele doua parti
int s,d; //nodul sursa si cel destinatie
int cmax,cmin; //cuplajul maxim de cost minim
//nodurile [1,a] sunt din prima multime iar nodurile [a+1,a+b] sunt din a 2-a multime

inline void add(struct nod n[], struct lista l[], int poz, int x, int y, int z, int mu)
{
	l[poz].n=y; l[poz].c=z; l[poz].m=mu; l[poz].p=n[x].p; n[x].p=poz;
}

void read()
{
	int i;
	scanf("%d %d %d\n",&a,&b,&nrm);
	for(i=1;i<=nrm;i++)
		scanf("%d %d %d\n",&m[i].p,&m[i].q,&m[i].c);
}

void init()
{
	int i;
	
	//calculam nodul sursa si cel destinatie
	s=a+b+1;
	d=s+1;
	
	//trebuie sa facem muchiile initiale in graf
	for(i=1;i<=nrm;i++)
	{
		nrl++; //facem loc in cele 2 liste
		add(n,l,nrl,m[i].p,a+m[i].q,m[i].c,i);  //graf normal
		add(nt,lt,nrl,a+m[i].q,m[i].p,m[i].c,i); //graful transpus
	}
	
	//trebuie adaugate noduri de la sursa
	for(i=1;i<=a;i++)
	{
		nrl++; //loc
		add(n,l,nrl,s,i,0,nrm+i);  //graf normal
		add(nt,lt,nrl,i,s,0,nrm+i); //graful transpus
	}
	
	//adaugam noduri catre destinatie
	for(i=a+1;i<=a+b;i++)
	{
		nrl++; //loc
		add(n,l,nrl,i,d,0,nrm+i);  //graf normal
		add(nt,lt,nrl,d,i,0,nrm+i); //graful transpus
	}
}

void bf()
{
	int st,dr,el;
	int i,j;
	
	//initializam distantele
	for(i=1;i<=d;i++)
		x[i]=inf;
	
	//initializam vectorul de vizite si cele de atingeri
	for(i=1;i<=d;i++)
		y[i]=z[i]=viz[i]=0;
	
	//initializam coada
	st=dr=el=1; c[1]=s; x[s]=0;
	
	while(el)
	{
		i=c[st%nmax];
		//facem parcurgerea normala
		for(j=n[i].p;j;j=l[j].p) //toate nodurile vecine
			if(!m[l[j].m].viz) //daca muchia nu a fost deja folosita
				if(x[i]+l[j].c<x[l[j].n]) //daca ajung cu cost mai bun
				{
					x[l[j].n]=x[i]+l[j].c; //salvez noul cost
					y[l[j].n]=i; //nodul din care am atins
					z[l[j].n]=l[j].m; //muchia cu care am atins
					if(!viz[l[j].n]) //daca nodul nu se afla deja in coada
						dr++,el++,c[dr%nmax]=l[j].n,viz[l[j].n]=1; //il punem
				}
		//facem parcurgerea in sens invers
		for(j=nt[i].p;j;j=lt[j].p) //toate nodurile vecine
			if(m[lt[j].m].viz) //daca muchia a fost folosita
				if(x[i]-lt[j].c<x[lt[j].n]) //daca ajung cu cost mai bun
				{
					x[lt[j].n]=x[i]-lt[j].c; //salvez noul cost
					y[lt[j].n]=i; //nodul din care am atins
					z[lt[j].n]=lt[j].m; //muchia cu care am atins
					if(!viz[lt[j].n]) //daca nodul nu se afla deja in coada
						dr++,el++,c[dr%nmax]=lt[j].n,viz[lt[j].n]=1; //il punem
				}
		viz[i]=0,st++,el--; //inaintam in coada
	}
}

void cmcm()
{ //calculam cuplajul maxim de cost minim
	int i;
	do
	{
		//facem lant de ameliorare
		bf();
		
		if(x[d]!=inf)
		{ //daca am atins nodul destinatie
			cmax++; //crestem cuplajul
			cmin+=x[d]; //crestem costul
			
			//refacem lantul de ameliorare
			for(i=d;i!=s;i=y[i])
				m[z[i]].viz=1-m[z[i]].viz; //sens normal
		}
	}
	while(x[d]!=inf); //cat timp atingem nodul destinatie
}

void write()
{
	int i;
	printf("%d %d\n",cmax,cmin);
	for(i=1;i<=nrm;i++)
		if(m[i].viz)
			printf("%d ",i);
}

int main()
{
	freopen(infile,"r",stdin);
	freopen(outfile,"w",stdout);
	
	read();
	init();
	cmcm();
	write();
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}