//poj 2455 Secret Milking Machine
//二分 + 最大流
//题意:
//输入第一行3个数为结点数,边数,路径数
//接下来为每条边的信息
//要求找出对应路径数中每条边都尽量小,输出这些路径中的边最长边为多少
//每条边只能用一次
//思路:
//对路径中的最长边进行二分,之后用最大流在符合边长限制的边中找看看有几条从
//起点 1 到终点 n的路,若大于限制的路径数就向左二分,反之向右二分
//注意:
//dinic:广搜时记得要有容量的且端点没分过层的才可以进行分层;
//深搜时求流向下一结点的流量为流到该结点的流量flow减去已经从该结点
//流出去的流量tmp,并和现在遍历到得边的容量相比,取小的往下一节点流,
//m = min(edge[i].cap, flow - tmp);最后若从目前结点没有流量流出,
//则把它的层标记为-1,即下次不能流到这一结点了
//具体看代码注释
#define infile freopen("in.txt", "r", stdin);
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int INF = 1<<30;
const int N = 205;
struct LINE
{
int st, ed, dis;
}line[N*N];
struct EDGE
{
int st, ed, dis, cap, next;
}edge[2*N*N];
int eid;
int head[N], level[N];
void add_edge(int st, int ed, int dis)
{
edge[eid].st = st;
edge[eid].ed = ed;
edge[eid].dis = dis;
edge[eid].cap = 1; //每条边只能用一次,所以容量为 1
edge[eid].next = head[st];
head[st] = eid++;
edge[eid].st = ed; //双向边,建反向边
edge[eid].ed = st;
edge[eid].dis = dis;
edge[eid].cap = 1;
edge[eid].next = head[ed];
head[ed] = eid++;
}
bool bfs(int source, int sink)
{
memset(level, 0, sizeof(level));
queue<int>que;
que.push(1);
level[1] = 1;
while(!que.empty())
{
int now = que.front();
que.pop();
for(int i = head[now]; i != -1; i = edge[i].next)
{
int ed = edge[i].ed;
if(edge[i].cap > 0 && level[ed] == 0) //边要有容量且结点还没被分层才对它分层
{
level[ed] = level[now] + 1;
que.push(ed);
}
}
}
return level[sink];
}
int dfs(int now, int sink, int flow)
{
if(now == sink)
return flow;
int tmp = 0, f;
for(int i = head[now]; i != -1; i = edge[i].next)
{
int ed = edge[i].ed;
int m = min(edge[i].cap, flow - tmp); //流到下一结点的流量
//流到now结点的流量为flow,从now流出去的流量为tmp
//所以个人觉得这里的 tmp < flow 可以不用,因为上面的最小值让
if(level[now] + 1 == level[ed] && edge[i].cap > 0 &&
tmp < flow && (f = dfs(ed, sink, m)))
{
edge[i].cap -= f;
edge[i^1].cap += f;
tmp += f;
}
}
if(tmp == 0)
level[now] = -1;
return tmp;
}
int dinic(int source, int sink)
{
int flow = 0;
while(bfs(source, sink)) //广搜进行分层
flow += dfs(source, sink, INF); //深搜找最大流
return flow;
}
void binarySearch(int n_node, int n_edge, int limit, int high)
{
int low = 1;
while(low < high) //对路径的最长边二分
{
eid = 0;
memset(head, -1, sizeof(head));
int mid = low + (high-low)/2;
for(int i = 0; i < n_edge; ++i)
if(line[i].dis <= mid) //把符合要求的边都加入邻接表中
add_edge(line[i].st, line[i].ed, line[i].dis);
int flow = dinic(1, n_node);
if(flow >= limit)
high = mid;
else
low = mid + 1;
}
printf("%d\n", low);
}
int main()
{
//infile
int n_node, n_edge, limit;
while(scanf("%d%d%d", &n_node, &n_edge, &limit) != EOF)
{
int m = 0;
for(int i = 0; i < n_edge; ++i)
{
scanf("%d%d%d", &line[i].st, &line[i].ed, &line[i].dis);
m = m < line[i].dis ? line[i].dis : m; //记录最长边
}
binarySearch(n_node, n_edge, limit, m);
}
return 0;
}