Cod sursa(job #633485)

Utilizator claudiumihailClaudiu Mihail claudiumihail Data 13 noiembrie 2011 20:43:15
Problema Cuplaj maxim de cost minim Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.77 kb
#include <fstream>
#include <iostream>
#include <cstring>
#include <vector>
#include <bitset>
#include <queue>
#include <cstdlib>

#define minimum(a,b)	\
({						\
	typeof(a) _a = a;	\
	typeof(b) _b = b;	\
	_a<=_b?_a:_b;		\
})

#define MAXN 700
#define INF 0x3f3f3f3f

using namespace std;

typedef unsigned short uint16;
typedef unsigned int uint32;

struct Edge
{
	Edge() :
		node(0),
		cost(0)
	{}
	Edge(const uint16 n, const short c) :
		node(n),
		cost(c)
	{}
	
	uint16 node;
	short cost;
};

typedef vector<vector<Edge> > Graph;

inline void AddSource(Graph& graph, const uint16 n, int** capacity)
{
	for (int i=1; i<=n; ++i)
	{
		graph[i].push_back(Edge(0,0));
		graph[0].push_back(Edge(i,0));
		
		capacity[0][i] = 1;
	}
}

inline void AddSink(Graph& graph, const uint16 n, const uint16 m, int** capacity)
{
	const uint16 dest = n+m+1;
	for (int i=1; i<=m; ++i)
	{
		graph[n+i].push_back(Edge(dest,0));
		graph[dest].push_back(Edge(n+i,0));
		
		capacity[n+i][dest] = 1;
	}
}

template<typename T>
class CQueue
{
public:
	CQueue(const size_t cap) :
		current(0),
		capacity(cap),
		size(0)
	{
		Q = (T*)malloc((cap+1)*sizeof(T));
	}
	
	T front() const
	{
		return Q[current];
	}
	
	void push(const T& elem)
	{
		const size_t pos = (current+size) % capacity;
		size++;
		Q[pos] = elem;
	}
	
	void pop()
	{
		if (size != 0)
		{
			size--;
			current++;
			current %= capacity;
		}
	}
	
	bool empty() const
	{
		return (size == 0);
	}
	
	void clear()
	{
		current = 0;
		size = 0;
	}
	
	~CQueue()
	{
		free(Q);
	}

private:
	T* Q;
	size_t current;
	size_t capacity;
	size_t size;
};

CQueue<uint16> Q(MAXN);

bool BellmanFord(const Graph &graph,
				 int **capacity,
				 int **flow,
				 const uint32 n,
				 const uint16 s,
				 int dist[],
				 int& minFlow
				)
{
	//queue<uint16> Q;
	//uint16 Q[n+1];
	uint16 count[MAXN]={0};
	int parent[MAXN]={-1};
	bool neg_cycle=false;
	bitset<MAXN> inQ;
	
	memset(dist,0x3f,n*sizeof(int));
	dist[s]=0;

	Q.push(s);
	inQ[s]=true;
	
	//cout << "check 1\n";

	while(!Q.empty() && !neg_cycle)
	{
		const uint16 node = Q.front();
		Q.pop();
		inQ[node]=false;
		
		//cout << "Popped " << node << endl;

		for (uint32 j=0; j<graph[node].size(); ++j)
		{
			if (capacity[node][graph[node][j].node] - flow[node][graph[node][j].node] > 0
				&& dist[node] + graph[node][j].cost < dist[graph[node][j].node])
			{
				dist[graph[node][j].node] = dist[node] + graph[node][j].cost;
				parent[graph[node][j].node] = node;
				
				if(!inQ[graph[node][j].node])
				{
					if(count[graph[node][j].node]>n)
					{
						neg_cycle=true;
					}
					else
					{
						Q.push(graph[node][j].node);
						inQ[graph[node][j].node]=true;
						count[graph[node][j].node]++;
						
						//cout << "Pushed " << graph[node][j].node << endl;
					}
				}
			}
		}
	}
	
	Q.clear();
	
	minFlow = INF;
	if (dist[n-1] < INF)
	{	
		for (int i=n-1; i>0; i = parent[i])
		{
			//cout << i << " ";
			minFlow = minimum(minFlow, capacity[parent[i]][i] - flow[parent[i]][i]);
		}
		//cout << endl;
		
		for (int i=n-1; i>0; i = parent[i])
		{
			flow[parent[i]][i] += minFlow;
			flow[i][parent[i]] -= minFlow;
		}
		
		//cout << "dist[n-1] = " << dist[n-1] << endl;
		//cout << "minFlow = " << minFlow << endl;
		
		minFlow *= dist[n-1];
		
		
		//cout << "Current flow is = " << minFlow << endl << endl;
	}

	return neg_cycle;
}

int MinimumCostMaximumMatching
(
	const Graph& graph,
	uint32 uGraphSize,
	int **capacity,
	int **flow,
	int dist[]
)
{
	int minFlow = 0;
	int totalMinFlow = 0;

	while (minFlow != INF)
	{
		totalMinFlow += minFlow;
		BellmanFord(graph, capacity, flow, uGraphSize, 0, dist, minFlow);
	}
	
	return totalMinFlow;
}

int ConstructSolution
(
	const uint16 n,
	const uint16 m,
	int** capacity,
	int** flow,
	int** edgeIndices,
	/*[out]*/vector<uint16>& vEdges
)
{
	int numEdges = 0;

	for (uint16 i=1; i<=n; ++i)
	{
		for (uint16 j=n+1; j<=n+m+1; ++j)
		{
			if (capacity[i][j] && flow[i][j])
			{
				numEdges++;
				vEdges.push_back(edgeIndices[i][j]);
				break;
			}
		}
	}
	
	return numEdges;
} 

int main()
{
	uint16 n,m;
	uint32 E;
	int **capacity, **flow, **edgeIndices, *dist;
	fstream fin("cmcm.in", fstream::in);
	fstream fout("cmcm.out", fstream::out);
	Graph graph;
	vector<uint16> vEdges;
	
	fin >> n >> m >> E;
	//cout << n << " " << m << " " << E << endl;
	
	const uint16 uGraphSize = n+m+2;
	
	graph.resize(uGraphSize);
	dist = new int[uGraphSize];

	capacity = new int*[uGraphSize];
	flow = new int*[uGraphSize];
	edgeIndices = new int*[uGraphSize];
	for (int i=0; i<uGraphSize; ++i)
	{
		capacity[i] = new int[uGraphSize];
		memset(capacity[i], 0, sizeof(int)*uGraphSize);
		
		flow[i] = new int[uGraphSize];
		memset(flow[i], 0, sizeof(int)*uGraphSize);
		
		edgeIndices[i] = new int[uGraphSize];
		memset(edgeIndices[i], 0, sizeof(int)*uGraphSize);
	}
	
	// read and build graph
	for (uint32 i=0; i<E; ++i)
	{
		uint16 x, y;
		short c;
		fin >> x >> y >> c;
		
		//cout << x << " " << y << " " << c << endl;
		
		graph[x].push_back(Edge(n+y,c));
		graph[n+y].push_back(Edge(x,-c));
		
		capacity[x][n+y] = 1;
		edgeIndices[x][n+y] = i;
	}
	
	AddSource(graph, n, capacity);
	AddSink(graph, n, m, capacity);
	
	// perform minim cost matching
	int totalMinFlow = MinimumCostMaximumMatching(graph, uGraphSize, capacity, flow, dist);
	//cout << totalMinFlow << endl;
	
	int numEdges = ConstructSolution(n, m, capacity, flow, edgeIndices, vEdges);
	
	fout << numEdges << " " << totalMinFlow << "\n";
	for (uint16 i=0; i<numEdges; ++i)
		fout << vEdges[i]+1 << " ";
	fout << "\n";
	
	fin.close();
	fout.close();
	return 0;
}