#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;
}