#include <cstdio>
#include <cassert>
#include <algorithm>
#include <vector>
#include <list>
#include <queue>
#include <cstdlib>
#include <cstring>
using namespace std;
#define _submit
#ifdef _submit
#define InFile "critice.in"
#define OtFile "critice.out"
#else
#define InFile "fis.in"
#define OtFile "fis.out"
#endif
class edge {
private:
int toNod, flow, capacity, ID;
edge* dup;
edge(int n1, int n2, int cap, int nr) {
toNod = n2;
capacity = cap;
flow = 0;
ID = nr;
}
void assignDup(edge *E) {
dup = E;
}
bool isSaturated() {
return (capacity - flow == 0) || (capacity + flow == 0);
}
friend class graph;
};
class graph {
private:
vector< list<edge> > adiac;
int edgeCounter;
public:
graph(int nrNod) {
adiac.resize(nrNod);
edgeCounter = 0;
}
void newEdge(int n1, int n2, int cap) {
adiac[n1].push_back(edge(n1, n2, cap, edgeCounter));
adiac[n2].push_back(edge(n2, n1, cap, edgeCounter));
adiac[n1].back().assignDup(&adiac[n2].back());
adiac[n2].back().assignDup(&adiac[n1].back());
edgeCounter++;
}
int sendFlows(vector<int>& parent, vector<int>& capToParent, vector<int*>& flowToParent, vector<int*>& flowToParentDup, queue<int>& Q) {
while (!Q.empty())
Q.pop();
int endNod = adiac.size() - 1;
int s = 0;
memset(&parent[0], 0xFF, parent.size() * sizeof(parent[0]));
Q.push(0);
parent[0] = -2;
while (!Q.empty()) {
int t = Q.front();
Q.pop();
for (auto i = adiac[t].begin(); i != adiac[t].end(); ++i) {
if (parent[i->toNod] != -1 || i->capacity - i->flow == 0)
continue;
if (i->toNod == endNod) {
int M = i->capacity - i->flow;
int curNod = t;
while (parent[curNod] != -2) {
int availableFlow = capToParent[curNod] - *flowToParent[curNod];
if (!availableFlow)
break;
if (availableFlow < M)
M = availableFlow;
curNod = parent[curNod];
}
if (parent[curNod] != -2)
continue;
i->flow += M;
i->dup->flow -= M;
curNod = t;
while (parent[curNod] != -2) {
*flowToParent[curNod] += M;
*flowToParentDup[curNod] -= M;
curNod = parent[curNod];
}
s += M;
}
else {
int curNod = i->toNod;
parent[curNod] = t;
capToParent[curNod] = i->capacity;
flowToParent[curNod] = &i->flow;
flowToParentDup[curNod] = &i->dup->flow;
Q.push(curNod);
}
}
}
return s;
}
int EdmondsKarp() {
int s = 0;
vector<int> parent(adiac.size());
vector<int> capToParent(adiac.size());
vector<int*> flowToParent(adiac.size());
vector<int*> flowToParentDup(adiac.size());
queue<int> Q;
while (true) {
int res = sendFlows(parent, capToParent, flowToParent, flowToParentDup, Q);
if (!res)
break;
s += res;
}
return s;
}
void DFSnesaturat(int nod, vector<char>& visited) {
visited[nod] = 1;
for (auto i = adiac[nod].begin(); i != adiac[nod].end(); ++i)
if (!visited[i->toNod] && !i->isSaturated())
DFSnesaturat(i->toNod, visited);
}
void getCriticalEdges(vector<int>& sol) {
EdmondsKarp();
vector<char> reachableFromSource(adiac.size(), 0);
DFSnesaturat(0, reachableFromSource);
vector<char> reachableFromSink(adiac.size(), 0);
DFSnesaturat(adiac.size() - 1, reachableFromSink);
int n1, n2;
for (auto i = adiac.begin(); i != adiac.end(); ++i)
for (auto j = i->begin(); j != i->end(); ++j) {
n1 = distance(adiac.begin(), i);
n2 = j->toNod;
if (j->ID >= 0 && j->isSaturated() && ((reachableFromSink[n1] && reachableFromSource[n2]) || (reachableFromSink[n2] && reachableFromSource[n1]))) {
sol.push_back(j->ID);
j->dup->ID = -1;
}
}
}
};
int main() {
assert(freopen(InFile, "r", stdin));
assert(freopen(OtFile, "w", stdout));
int N, M;
scanf("%d%d", &N, &M);
graph G(N);
for (int i = 0; i < M; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
G.newEdge(a - 1, b - 1, c);
}
vector<int> sol;
sol.reserve(M);
G.getCriticalEdges(sol);
printf("%d\n", sol.size());
for (auto i = sol.begin(); i != sol.end(); ++i)
printf("%d\n", (*i) + 1);
return 0;
}