using static IO;
public class IO
{
public static IO Cin = new();
public static StreamReader reader = new(Console.OpenStandardInput());
public static StreamWriter writer = new(Console.OpenStandardOutput());
public static implicit operator string(IO _) => reader.ReadLine();
public static implicit operator char[](IO _) => reader.ReadLine().ToArray();
public static implicit operator int(IO _) => int.Parse(reader.ReadLine());
public static implicit operator double(IO _) => double.Parse(reader.ReadLine());
public static implicit operator string[](IO _) => reader.ReadLine().Split();
public static implicit operator int[](IO _) => Array.ConvertAll(reader.ReadLine().Split(), int.Parse);
public void Deconstruct(out int a, out int b, out int c,out int d) { int[] r = Cin; (a, b, c, d) = (r[0], r[1], r[2], r[3]); }
public void Deconstruct(out int a, out int b, out int c) { int[] r = Cin; (a, b, c) = (r[0], r[1], r[2]); }
public static IEnumerable<int> MakeRange(int start, int count) => Enumerable.Range(start, count);
public static T[] MakeArray<T>(int count) where T : new() => MakeRange(0, count).Select(_ => new T()).ToArray();
public static object? Cout { set { writer.Write(value); } }
public static object? Coutln { set { writer.WriteLine(value); } }
public static void Main() { Program.Coding(); writer.Flush(); }
}
class Program
{
const int source = 0;
public static void Coding()
{
checked
{
(int nodeCount, int lineCount, int timeLimit, int minFlow) = Cin;
FlowGraph graph = new(nodeCount * (timeLimit + 1));
int sink = graph.Count - 1;
foreach (int[] input in Enumerable.Range(0, lineCount).Select(_ => (int[])Cin))
{
int start = input[0] - 1;
int end = input[1] - 1;
int wave = input[2];
for (int next = nodeCount; next < graph.Count; next += nodeCount)
{
graph.AddLine(start + next - nodeCount, end + next, 1, wave);
graph.AddLine(end + next - nodeCount, start + next, 1, wave);
}
}
for (int me = 0; me < nodeCount; me++)
{
for (int next = me + nodeCount; next < graph.Count; next += nodeCount)
{
graph.AddLine(next - nodeCount, next, 614, 0);
}
}
int low = 1, high = 100_002;
while (low < high)
{
int mid = (low + high) / 2;
if (graph.GetMaxFlow(source, sink, mid) >= minFlow) high = mid;
else low = mid + 1;
}
Cout = high == 100_002 ? -1 : high;
}
}
}
class FlowLine
{
public int Start { get; }
public int End { get; }
public int Capacity { get; }
public int Flow { get; set; } = 0;
public FlowLine Reverse { get; }
public int Remaining => Capacity - Flow;
public int Wave { get; }
public FlowLine(int start, int end, int capacity, int wave, FlowLine? reverse = null)
{
this.Start = start;
this.End = end;
this.Capacity = capacity;
this.Wave = wave;
this.Reverse = reverse ?? new(end, start, 0, wave, this);
}
}
class FlowGraph
{
public FlowGraph(int size)
{
graph = MakeArray<List<FlowLine>>(Count = size);
}
public void AddLine(int start, int end, int capacity, int wave)
{
FlowLine line = new(start, end, capacity, wave);
graph[start].Add(line);
graph[end].Add(line.Reverse);
}
public int GetMaxFlow(int source, int sink, int waveLimit)
{
int totalFlow = 0;
while (true)
{
FlowLine[]? parent = new FlowLine[Count];
Queue<int> queue = new();
queue.Enqueue(source);
while (queue.TryDequeue(out int me) && parent[sink] is null)
{
foreach (FlowLine line in graph[me])
{
if (line.Remaining > 0 && parent[line.End] is null && line.End != source && line.Wave <= waveLimit)
{
parent[line.End] = line;
queue.Enqueue(line.End);
if (line.End == sink) break;
}
}
}
if (parent[sink] is null) break;
int addFlow = int.MaxValue;
for (FlowLine? line = parent[sink]; line is not null; line = parent[line.Start])
{
addFlow = Math.Min(addFlow, line.Remaining);
}
for (FlowLine? line = parent[sink]; line is not null; line = parent[line.Start])
{
line.Flow += addFlow;
line.Reverse.Flow -= addFlow;
}
totalFlow += addFlow;
}
ClearFlow();
return totalFlow;
}
public int Count { get; }
private readonly List<FlowLine>[] graph;
private void ClearFlow()
{
foreach (var lines in graph)
{
foreach (var line in lines)
{
line.Flow = 0;
}
}
}
}