Cod sursa(job #255676)

Utilizator stocarulCosmin-Mihai Tutunaru stocarul Data 10 februarie 2009 10:24:05
Problema Cuplaj maxim in graf bipartit Scor 20
Compilator c Status done
Runda Arhiva educationala Marime 3.87 kb
#include<stdio.h>
#define infile "cuplaj.in"
#define outfile "cuplaj.out"
#define nmax (20*1000+5)
#define mmax (nmax+100*1000+1)
#define inf ~(1<<31)
struct lista
	{
	int n,p,f; //nodul pozitia si fluxul folosit pe acest arc
	} l[mmax],lt[mmax]; //lista pt graful normal si pt graful transpus
char viz[nmax]; //vector pt vizite
int p[nmax],pt[nmax]; //pozitiile din lista pt graful normal si pt cel transpus
int le,ri; //lungimea celor doua grupuri de noduri
int m; //numarul de muchii
int st,fi; //cele doua noduri pe care le adaugam a.i. sa avem o retea
int flux; //fluxul maxim din cuplaj

//adauga arcul (x,y) in lista
void add(struct lista l[mmax], int p[nmax], int m, int x, int y)
	{
	l[m].n=y; l[m].p=p[x]; p[x]=m;
	}

void citire()
	{
	int i,x,y;
	scanf("%d %d %d\n",&le,&ri,&m); //nuymarul nodurilor din fiecare grupa, si numarul de muchii dintre noduri
	for(i=1;i<=m;i++) //fiecare muchie in parte
		{
		scanf("%d %d\n",&x,&y);
		y+=le; //numerotarea nodurilor din grupa 2 incepe de la l
		add(l,p,i,x,y); //graful normal
		add(lt,pt,i,y,x); //graful transpus
		}
	}

//transformam graful intr-o retea de transport
void initializare()
	{
	int i;
	st=le+ri+1; fi=st+1; //nuymarul de ordine al celor doua noduri (start si final)
	for(i=1;i<=le;i++) //trebuie sa adaugam arc de la nodul de start la toate nodurile din grupa l
		{
		++m;
		add(l,p,m,st,i); //adaugam in graful normal
		add(lt,pt,m,i,st); //adaugam in graful transpus
		}
	for(i=1;i<=ri;i++)//trebuie sa adaugam arc de la fiecare nod din grupa a 2-a la nodul final
		{
		++m;
		add(l,p,m,le+i,fi); //graful normal
		add(lt,p,m,fi,le+i); //graful transpus
		}
	}

//modifica fluxul pentru un arc din lista
void modifica_flux(struct lista l[mmax], int p[nmax], int x, int y, int f)
	{
	int ul=p[x]; //pozitia copilului
	while(ul) //cat timp are copil
		{
		if(l[ul].n==y) { l[ul].f=f; break; } //am gasit nodul..modific fluxul
		ul=l[ul].p; //frasu
		}
	}

//apelam un nod (cu fluxul f)....si returnam fluxul nefolosit de nod
int dfs(int x, int f)
	{
	viz[x]=1; //marcam ca vizitat nodul x
	if(x==fi) { flux+=f; return 0; } //am atins finalul...salvam fluxul si returnam 0
	int ul,c;
	for(ul=p[x];ul&&f;ul=l[ul].p) //parcurgem copii lui x
		if(!viz[l[ul].n]&&!l[ul].f) //daca n-am mai vizitat nodul, si daca arcul nu este satura (fluxul este 0)
			{
			c=dfs(l[ul].n,1); //apelam nodul cu fluxul 1
			viz[l[ul].n]=0; //devizitam nodul
			if(!c) //daca nu a returna flux...deci a folosit tot
				{
				l[ul].f=1; //saturam arcul
				modifica_flux(lt,pt,x,l[ul].n,1); //modificam fluxul si in lista pt graful transpus
				f-=1; //scadem ca am folosit din flux
				}
			}
	for(ul=pt[x];ul&&f;ul=lt[ul].p) //parcurgem copii lui x in graful transpus (deci destinatie-sursa)
		if(!viz[lt[ul].n]&&lt[ul].f) //daca nodul nu a mai fost vizitat si daca avem flux (aici trebuie sa avem flux)
			{
			c=dfs(lt[ul].n,1); //apelam nodul cu fluxul 1...
			viz[lt[ul].n]=0; //devizitam nodul
			if(!c) //daca nu a returnat flux....deci a folosit tot
				{
				lt[ul].f=0; //scadem fluxul
				modifica_flux(l,p,x,lt[ul].n,0); //modificam fluxul si in graful normal
				f-=1; //scadem k am folosit 1 din flux
				}
			}
	return f; //returnam fluxul nefolosit
	}

void  afisare()
	{
	int i,ul;
	printf("%d\n",flux); //afisem fluxul maxim
	for(i=1;i<=le;i++) //luam fiecare nod din primul grup
		{
		ul=p[i]; //ii luam pozitia din lista
		while(ul)
			{
			if(l[ul].f==1) { printf("%d %d\n",i,l[ul].n-le); break; }//afisem muchia si oprim 
			ul=l[ul].p; //frasu
			}
		}
	}

int main()
{
freopen(infile,"r",stdin);
freopen(outfile,"w",stdout);

citire(); //citim graful
initializare(); //transformam graful in retea de transport
dfs(st,inf); //parcurgem reteaua din nodul de start cu flux infinit...si aflam fluxul total
afisare(); //afisem

fclose(stdin);
fclose(stdout);
return 0;
}