Cod sursa(job #651519)

Utilizator blustudioPaul Herman blustudio Data 20 decembrie 2011 18:21:18
Problema Flux maxim de cost minim Scor 50
Compilator cpp Status done
Runda Arhiva educationala Marime 5.03 kb
//http://infoarena.ro/job_detail/605435?action=view-source
#include <fstream>
#include <vector>
#include <set>
#include <iostream>
using namespace std;

struct muchie
{
	int cost; //Costul pentru a parcurge muchia
	unsigned short int b; //Nodul B
};
struct nod
{
	bool vizitat;
	int cost;
	vector<muchie> vecini;
};

#define INFINIT 0x3f3f3f

int flux_maxim;
int flux[351][351];
int capacitate[351][351];
nod noduri[351]; //Nodurile grafului
short int drum[351]; //Vector de tati al drumului minim
unsigned short int n; //Numarul de noduri
unsigned short int m; //Nr. de muchii
unsigned short int sursa, destinatie;
bool drum_ameliorare; //Daca mai exista drum de ameliorare;
int cost;

struct comparare
{
	inline bool operator() (const short int& lhs, const short int& rhs) const
	{
		return noduri[lhs].cost < noduri[rhs].cost;
	}
};

multiset<short int, comparare> lista; //Heap pt distanta minima fata de sursa

void BF()
{
	bool relaxeaza = true;
	for (unsigned short int i = 1; i <= n; i++)
		noduri[i].cost = INFINIT; //Costul pt. a ajunge la restul nodurilor e infinit
	noduri[sursa].cost = 0; //Costul pt. a ajunge la sursa e 0
	for (unsigned short int k = 1; (k <= n) && (relaxeaza == true); k++)
	{
        //Parcurgem toate nodurile daca am avut vreo relaxare
        relaxeaza = false; //Presupunem ca nu se face nici o relaxare
        for (unsigned short int i = 1; i <= n; i++)
        {
            for (unsigned int j = 0; j < noduri[i].vecini.size(); j++) //Parcurgem toate muchiile
            {
                if (capacitate[i][noduri[i].vecini[j].b] > flux[i][noduri[i].vecini[j].b])
                {
                    if ((noduri[i].cost + noduri[i].vecini[j].cost) < noduri[noduri[i].vecini[j].b].cost)
                    {
                        //Relaxam muchiile
                        noduri[noduri[i].vecini[j].b].cost = noduri[i].cost + noduri[i].vecini[j].cost;
                        relaxeaza = true;
                    }
                }
            }
        }
	}
	cost = noduri[destinatie].cost;
}

inline int Dijkstra()
{
    for (unsigned short int i = 1; i <= n; i++)
        for (unsigned int j = 0; j < noduri[i].vecini.size(); j++)
            noduri[i].vecini[j].cost += noduri[i].cost - noduri[noduri[i].vecini[j].b].cost;

	for (unsigned short int i = 1; i <= n; i++)
	{
		noduri[i].vizitat = false; //Nu am vizitat nici und nod
		noduri[i].cost = INFINIT; //Costul pt. a ajunge la restul nodurilor e infinit
	}

	short int nod_curent = sursa;
	noduri[sursa].cost = 0; //Costul pt. a ajunge la sursa e 0
	lista.insert(sursa);

	while (lista.empty() == false)
	{
		//Cautam nodul nevizitat cel mai apropiat de sursa
		nod_curent = *lista.begin();
		lista.erase(lista.begin());

		noduri[nod_curent].vizitat = true; //Marcam nodul curent ca vizitat

		for (unsigned short int i = 0; i < noduri[nod_curent].vecini.size(); i++) //Parcurgem toti vecinii nodului curent
		{
		    if (capacitate[nod_curent][noduri[nod_curent].vecini[i].b] > flux[nod_curent][noduri[nod_curent].vecini[i].b])
			{
                if ((noduri[nod_curent].cost + noduri[nod_curent].vecini[i].cost) < noduri[noduri[nod_curent].vecini[i].b].cost)
                {
                    drum[noduri[nod_curent].vecini[i].b] = nod_curent;
                    noduri[noduri[nod_curent].vecini[i].b].cost = noduri[nod_curent].cost + noduri[nod_curent].vecini[i].cost;
                    lista.insert(noduri[nod_curent].vecini[i].b);
                }
			}
		}
	}

	if (noduri[destinatie].vizitat == true)
	{
		drum_ameliorare = true;
		int capacitate_reziduala = INFINIT;
		nod_curent = destinatie;
		while (nod_curent != sursa)
		{
			if (capacitate_reziduala > (capacitate[drum[nod_curent]][nod_curent] - flux[drum[nod_curent]][nod_curent]))
				capacitate_reziduala = capacitate[drum[nod_curent]][nod_curent] - flux[drum[nod_curent]][nod_curent];
			nod_curent = drum[nod_curent];
		}
		nod_curent = destinatie;
		while (nod_curent != sursa)
		{
			flux[nod_curent][drum[nod_curent]] -= capacitate_reziduala;
			flux[drum[nod_curent]][nod_curent] += capacitate_reziduala;
			nod_curent = drum[nod_curent];
		}
		cost += noduri[destinatie].cost;
		return cost * capacitate_reziduala;
	}
	else
	{
		drum_ameliorare = false;
		return 0;
	}
}
inline void fmcm()
{
    BF();
    flux_maxim = 0;
	do {
		flux_maxim += Dijkstra();
	} while (drum_ameliorare == true);
}
inline void citire()
{
    ifstream fin("fmcm.in");
    int a, b, f, c;
    muchie l;
    fin >> n >> m >> sursa >> destinatie;
	for (unsigned int i = 1; i <= m ; i++)
	{
		fin >> a >> b >> f >> c;
        l.cost = c;
        l.b = b;
        noduri[a].vecini.push_back(l);
        l.b = a;
        l.cost = -c;
        noduri[b].vecini.push_back(l); //Muchia inversa
        capacitate[a][b] = f;
	}
    fin.close();
}
inline void scriere()
{
    ofstream fout("fmcm.out");
    fout << flux_maxim;
    fout.close();
}
int main()
{
    citire();
    fmcm();
    scriere();
    return 0;
}