Cod sursa(job #256498)

Utilizator stocarulCosmin-Mihai Tutunaru stocarul Data 11 februarie 2009 20:31:20
Problema Felinare Scor 8
Compilator c Status done
Runda Arhiva de probleme Marime 3.57 kb
#include<stdio.h>
#define infile "felinare.in"
#define outfile "felinare.out"
#define nmax (2*(9*1000+1))
#define mmax (2*nmax+20*1000+1)
#define inf ~(1<<31)
struct lista
	{
	int n,p,f; //nodul, pozitia si fluxul de pe acest arc
	} l[mmax], lt[mmax]; //lista normala si lista transpusa
int p[nmax], pt[nmax]; //pozitia din cele liste a nodurilor
int viz[nmax]; //vector de vizita
int st,fi; //nodul de start si nodul final pt reteaua de transport
int n,m; //numarul de noduri respectiv muchii
int flux; //aici vom calcula fluxul maxim

//adaugam arcul (x,y) in lista
inline 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;
	}

//modifica in lista de adiacenta a unui nod, fluxul
inline void modifica(struct lista l[mmax], int p[nmax], int x, int y, int f)
	{
	int ul=p[x]; //pozitia din lista a lu fisu
	while(ul)
		{
		if(l[ul].n==y) { l[ul].f=f; break; } //am gasit arcul....ii modificam fluxul si oprim
		ul=l[ul].p; //fiusu
		}
	}

void citire()
	{
	int i,x,y;
	scanf("%d %d\n",&n,&m); //numarul de linii si muchii
	for(i=1;i<=m;i++)
		{
		scanf("%d %d\n",&x,&y);
		y+=n; //fiind nevoiti ca dupa sa facem cuplaj maxim....nodurile din partea cealalta vor incepe numararea de la n+1
		add(l,p,i,x,y); //adaug arcul pt graful normal
		add(lt,pt,i,y,x); //adaug arcul pt graful transpus
		}
	}

//transformam graful in retea de transport...(avem nevoie sa facem dupa cuplaj maxim in graf bipartit)
void initializare()
	{
	int i;
	st=n+1; fi=st+1; //nodul de intrare si cel de iesire....
	for(i=1;i<=n;i++) //adaugam legatura de la nodul st la toate nodurile din prima grupa
		{
		++m; //facem loc in lista :P
		add(l,p,m,st,i); //adaugam in graful normal
		add(lt,pt,m,i,st); //adaugam si in graful transpus
		}
	for(i=1;i<=n;i++) //adaugam legatura de la toate nodurile din grupa a 2-a la nodul final...
		{
		++m; //facem loc in lista
		add(l,p,m,i+n,fi); //graful normal
		add(lt,pt,m,fi,i+n); //graful transpus
		}
	}

//facem parcurgere in adancime...pt a afla fluxul maxim in graf :P...bipartit
int dfs(int x, int f) //nodul in care ne aflam...si fluxul care il putem folosi
	{
	viz[x]=1; //il marcam ca vizitat
	if(x==fi) { flux+=f; return 0; } //am ajuns la nodul final...salvam fluxul...si returnam 0 (l-am folosit pe tot)
	int ul,c;
	for(ul=p[x];ul&&f;ul=l[ul].p) //trecem pe la fiecare copil al lui x
		if(!viz[l[ul].n]&&!l[ul].f) //daca nu a fost vizitat, si daca nu avem arcul saturat
			{
			c=dfs(l[ul].n,1); viz[l[ul].n]=0; //nodul e clar ca il putem apela doar cu flux 1
			if(!c) //daca nodul nu a returnat cost....l-a folosit :P
				{
				l[ul].f=1; //saturam arcul
				modifica(lt,pt,l[ul].n,x,1); //modificam fluxul si in lista transpusa
				f-=1; //scadem k am folosit din flux
				}
			}
	for(ul=pt[x];ul&&f;ul=lt[ul].p) //trecem pe la feicare copil al lui x in graful transpus
		if(!viz[lt[ul].n]&&lt[ul].f) //daca nodul nu a mai fost vizitat....si daca am flux (pt k parcurg arcul in sens invers)
			{
			c=dfs(lt[ul].n,1); viz[lt[ul].n]=0; //parcurgem nodul cu flux 1
			if(!c) //daca a fost folosit fluxul de pe acest nod
				{
				lt[ul].f=0; //scadem fluxul folosit
				modifica(l,p,lt[ul].n,x,0); //modificam fluxul si in lista normala a retelei
				f-=1; //am folosit fluxul :P
				}
			}
	return f; //returnam fluxul ramas :P
	}

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

citire(); //citire
initializare(); //transformam graful in retea de transport :P
dfs(st,inf);
printf("%d\n",(2*n)-flux);

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