poj 2455 Secret Milking Machine 二分+dinic求最大流
poj 2455 Secret Milking Machine 二分 + dinic求最大流
//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; }