POJ 2455 网络流 基础题 二分+网络流 dicnic 以及 sap算法
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8189 | Accepted: 2485 |
Description
The farm comprises N (2 <= N <= 200) landmarks (numbered 1..N) connected by P (1 <= P <= 40,000) bidirectional trails (numbered 1..P) and with a positive length that does not exceed 1,000,000. Multiple trails might join a pair of landmarks.
To minimize his chances of detection, FJ knows he cannot use any trail on the farm more than once and that he should try to use the shortest trails.
Help FJ get from the barn (landmark 1) to the secret milking machine (landmark N) a total of T times. Find the minimum possible length of the longest single trail that he will have to use, subject to the constraint that he use no trail more than once. (Note well: The goal is to minimize the length of the longest trail, not the sum of the trail lengths.)
It is guaranteed that FJ can make all T trips without reusing a trail.
Input
* Lines 2..P+1: Line i+1 contains three space-separated integers, A_i, B_i, and L_i, indicating that a trail connects landmark A_i to landmark B_i with length L_i.
Output
Sample Input
7 9 2
1 2 2
2 3 5
3 7 5
1 4 1
4 3 1
4 5 7
5 7 1
1 6 3
6 7 3
Sample Output
5
Hint
Huge input data,scanf is recommended.
Source
题意:
题意:FJ有N块地,这些地之间有P条双向路,每条路的都有固定的长度l。现在要你找出从第1块地到第n块地的T条不同路径,每条路径上的路不能与先前的路径重复,问这些路径中的最长路的最小是多少。
思路:二分答案+网络流判定。
二分枚举最大边权,重新建图,只保存权不超过最大边权的边。即如果边的长度小于等于我们规定的最大边权 则添加这条边 权值为1, 否则标记为0
然后在网络中起点终点间的容量是原图中的路径数,判断最大流是否>=T
只需要对模板就行修改下 之后二分即可 只需要修改添加边的地方 因为本题是双向边 所以添加的边以及其反方向边 都应该权值为cw
#include <stdio.h>
#include <string.h>
#define VM 222
#define EM 81111*2
#define inf 0x3f3f3f3f
struct Edge
{
int frm,to,cap,next;
}edge[EM]; int head[VM],dep[VM],ep,n; //dep为点的层次
void addedge (int cu,int cv,int cw) //第一条边下标必须为偶数
{
edge[ep].frm = cu;
edge[ep].to = cv;
edge[ep].cap = cw;
edge[ep].next = head[cu];
head[cu] = ep;
ep ++;
edge[ep].frm = cv;
edge[ep].to = cu;
edge[ep].cap = cw;
edge[ep].next = head[cv];
head[cv] = ep;
ep ++;
} int BFS (int src,int des) //求出层次图
{
int que[VM],i,front = 0,rear = 0;
memset (dep,-1,sizeof(dep));
que[rear++] = src;
dep[src] = 0;
while (front != rear)
{
int u = que[front++];
front = front%VM;
for (i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > 0&&dep[v] == -1) //容量大于0&&未在dep中
{
dep[v] = dep[u] + 1; //建立层次图
que[rear ++] = v;
rear = rear % VM;
if (v == des) //找到汇点 返回
return 1;
}
}
}
return 0;
}
int dinic (int src,int des)
{
int i,res = 0,top;
int stack[VM]; //stack为栈,存储当前增广路
int cur[VM]; //存储当前点的后继 跟head是一样的
while (BFS(src,des)) //if BFS找到增广路
{
memcpy (cur,head,sizeof (head));
int u = src; //u为当前结点
top = 0;
while (1)
{
if (u == des) //增广路已全部进栈
{
int min = inf,loc ;
for (i = 0;i < top;i ++) //找最小的增广跟并loc记录其在stack中位置
if (min > edge[stack[i]].cap) //以便退回该边继续DFS
{
min = edge[stack[i]].cap;
loc = i;
}
for (i = 0;i < top;i ++) //偶数^1 相当加1 奇数^1相当减1 当正向边 = 0&&路径不合适时,正加负减
{ //偶数是正向边,奇数是负向边,边从0开始
edge[stack[i]].cap -= min;
edge[stack[i]^1].cap += min;
} //将增广路中的所有边修改
res += min;
top = loc;
u = edge[stack[top]].frm; //当前结点修改为最小边的起点
}
for (i = cur[u];i != -1;cur[u] = i = edge[i].next) //找到当前结点对应的下一条边
if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])//不满足条件时,修改cur值(去掉不合适的占)eg:1-->2 1-->3 1-->4 有边 但只有
break; // 1-->4 这条边满足条件 就把1到2、3的边给去掉
if (cur[u] != -1) //当前结点的下一条边存在
{
stack[top ++] = cur[u]; //把该边放入栈中
u = edge[cur[u]].to; //再从下个点开始找
}
else
{
if (top == 0) //当前结点无未遍历的下一条边且栈空,DFS找不到下一条增广路
break;
dep[u] = -1; //当前结点不在增广路中,剔除该点
u = edge[stack[--top]].frm; //退栈 回朔,继续查找
}
}
}
return res;
}
struct IN
{
int x,y,c;
}q[EM];
int sovle(int mid,int src,int des,int m,int k)
{
ep = 0;
memset (head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
if(q[i].c<=mid)
addedge(q[i].x,q[i].y,1);
// addedge(q[i].y,q[i].x,1); }
if(dinic (src,des)>=k) return 1;
return 0;
}
int main ()
{
int n,m,v1,v2,w,k,i;
int src,des;
while (scanf ("%d %d %d",&n,&m,&k)!=EOF)
{
// ep = 0;
src=1;des=n;
// memset (head,-1,sizeof(head));
for(i=0;i<m;i++)
{
scanf("%d %d %d",&v1,&v2,&w);
q[i].x=v1;q[i].y=v2;q[i].c=w;
}
int left,right,mid,ans=-1;
left=0;right=1000000;
while(left<=right)
{
mid=(left+right)/2;
if(sovle(mid,src,des,m,k))
{
ans=mid;
right=mid-1;
}
else left=mid+1;
}
printf ("%d\n",ans);
}
return 0;
}
Sap 算法
#include <stdio.h>
#include <string.h>
#define VM 222
#define EM 81111*2
#define inf 0x3f3f3f3f struct Edge
{
int to, frm, nxt, cap;
}edge[EM]; int head[VM], ep, n, src, des;
int dep[VM], gap[VM]; //gap[x]=y:说明残留网络中dep[i]=x的个数为y void addedge(int u, int v, int c)
{
edge[ep].frm = u;
edge[ep].to = v;
edge[ep].cap = c;
edge[ep].nxt = head[u];
head[u] = ep++;
edge[ep].frm = v;
edge[ep].to = u;
edge[ep].cap = 0;
edge[ep].nxt = head[v];
head[v] = ep++;
} void BFS()
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1; //说明此时有1个dep[i] = 0
int que[VM], front = 0, rear = 0;
dep[des] = 0;
que[rear++] = des;
int u, v;
while (front != rear)
{
u = que[front++];
front = front%VM;
for (int i=head[u]; i!=-1; i=edge[i].nxt)
{
v = edge[i].to;
if (edge[i].cap != 0 || dep[v] != -1)
continue;
que[rear++] = v;
rear = rear % VM;
++gap[dep[v] = dep[u] + 1]; //求出各层次的数量
}
}
} int Sap()
{
int res = 0;
BFS();
int cur[VM];
int stack[VM], top = 0;
memcpy(cur, head, sizeof(head));
int u = src, i;
while (dep[src] < n)
{
if (u == des)
{
int temp = inf, inser = n;
for (i=0; i!=top; ++i)
if (temp > edge[stack[i]].cap)
{
temp = edge[stack[i]].cap;
inser = i;
}
for (i=0; i!=top; ++i)
{
edge[stack[i]].cap -= temp;
edge[stack[i]^1].cap += temp;
}
res += temp;
top = inser;
u = edge[stack[top]].frm;
} if (dep[u] != 0 && gap[dep[u] -1] == 0)//出现断层,无增广路
break;
for (i = cur[u]; i != -1; i = edge[i].nxt)//遍历与u相连的未遍历结点
if (dep[edge[i].to] != -1)
if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1) //层序关系, 找到允许
break; if (i != -1)//找到允许弧
{
cur[u] = i;
stack[top++] = i;//加入路径栈
u = edge[i].to;//查找下一个结点
}
else //无允许的路径,修改标号 当前点的标号比与之相连的点中最小的多1
{
int min = n;
for (i = head[u]; i != -1; i = edge[i].nxt) //找到与u相连的v中dep[v]最小的点
{
if (edge[i].cap == 0)
continue;
if (min > dep[edge[i].to])
{
min = dep[edge[i].to];
cur[u] = i; //最小标号就是最新的允许弧
}
}
--gap[dep[u]]; //dep[u] 的个数变化了 所以修改gap
++gap[dep[u] = min + 1]; //将dep[u]设为min(dep[v]) + 1, 同时修改相应的gap[]
if (u != src) //该点非源点&&以u开始的允许弧不存在,退点
u = edge[stack[--top]].frm;
}
}
return res;
} struct IN
{
int x,y,c;
}q[EM];
int sovle(int mid,int m,int k)
{
//printf("jin\n");
ep = 0;
memset (head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
if(q[i].c<=mid)
{
addedge(q[i].x,q[i].y,1);
addedge(q[i].y,q[i].x,1);//不知道为什么 sap需要添加2次 相反边
}
}
if(Sap()>=k) return 1;
return 0;
}
int main ()
{
int m,v1,v2,w,k,i;
while (scanf ("%d %d %d",&n,&m,&k)!=EOF)
{
src=1;des=n;
for(i=0;i<m;i++)
{
scanf("%d %d %d",&v1,&v2,&w);
q[i].x=v1;q[i].y=v2;q[i].c=w;
}
int left,right,mid,ans=-1;
left=0;right=1000000;
while(left<=right)
{
mid=(left+right)/2;
if(sovle(mid,m,k))
{
ans=mid;
right=mid-1;
}
else left=mid+1;
}
printf ("%d\n",ans);
}
return 0;
}
POJ 2455 网络流 基础题 二分+网络流 dicnic 以及 sap算法的更多相关文章
- POJ 2455 Secret Milking Machine (二分 + 最大流)
题目大意: 给出一张无向图,找出T条从1..N的路径,互不重复,求走过的所有边中的最大值最小是多少. 算法讨论: 首先最大值最小就提醒我们用二分,每次二分一个最大值,然后重新构图,把那些边权符合要求的 ...
- cogs 728. [网络流24题] 最小路径覆盖问题 匈牙利算法
728. [网络流24题] 最小路径覆盖问题 ★★★☆ 输入文件:path3.in 输出文件:path3.out 评测插件时间限制:1 s 内存限制:128 MB 算法实现题8-3 最 ...
- cogs 14. [网络流24题] 搭配飞行员 二分图最大匹配 匈牙利算法
14. [网络流24题] 搭配飞行员 ★★ 输入文件:flyer.in 输出文件:flyer.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 飞行大队有 ...
- POJ 2391 Ombrophobic Bovines【二分 网络流】
题目大意:F个草场,P条道路(无向),每个草场初始有几头牛,还有庇护所,庇护所有个容量,每条道路走完都有时间,问所有奶牛都到庇护所最大时间最小是多少? 思路:和POJ2112一样的思路,二分以后构建网 ...
- POJ 2455Secret Milking Machine(二分+网络流之最大流)
题目地址:POJ2455 手残真浪费时间啊..又拖到了今天才找出了错误..每晚两道题不知不觉又变回了每晚一道题...sad.. 第一次在isap中忘记调用bfs,第二次则是遍历的时候竟然是从1開始遍历 ...
- POJ 2455 Secret Milking Machine (二分+无向图最大流)
[题意]n个点的一个无向图,在保证存在T条从1到n的不重复路径(任意一条边都不能重复)的前提下,要使得这t条路上经过的最长路径最短. 之所以把"经过的最长路径最短"划个重点是因为前 ...
- poj 2455 Secret Milking Machine 二分+最大流 sap
题目:p条路,连接n个节点,现在需要从节点1到节点n,不重复走过一条路且走t次,最小化这t次中连接两个节点最长的那条路的值. 分析:二分答案,对于<=二分的值的边建边,跑一次最大流即可. #in ...
- 2-sat基础题 uvalive 3211
蓝书325页的基础题 二分+2-sat //看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using n ...
- POJ 2455 Secret Milking Machine(搜索-二分,网络流-最大流)
Secret Milking Machine Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9658 Accepted: ...
随机推荐
- 详解虚拟机(windows)下搭建SVN服务器
安装前的准备 1.虚拟机的用户名最好是英文 2.严格按照步骤做,否则有可能不成功 3.如果安装失败,在虚拟机下的控制板完全下载VisualSVN-Server-2.7.7,重新安装 软件下载地址: h ...
- 在mac本上折腾android 开发环境
众所周知的原因,google的很多网站在国内无法访问,苦逼了一堆天朝程序员,下是在mac本上折腾android 开发环境的过程: 一.先下载android sdk for mac 给二个靠谱的网址: ...
- codeforces 559A(Gerald's Hexagon)
Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description Gera ...
- Definitions
Definitions and ODR Definitions are declarations that fully define the entity introduced by the decl ...
- Linux命令压缩与解压缩
zip格式的文件:zip和unzip zip 命令: # zip test.zip test.txt 它会将 test.txt 文件压缩为 test.zip ,当然也可以指定压缩包的目录,例如 /ro ...
- [Git]自译《Git版本控制管理》——1.介绍(二)_Git诞生
译者前言: 本系列译文为作者利用业余时间翻译,有些疏漏与翻译不到位的地方敬请谅解. 不过也很希望各位读者能给出中肯的建议. 方括号的注释,如[1][2]为译者注. ...
- jquery事件链式写法
<!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...
- C# Thread Programming Start
引言 1.理解多线程 2. 线程异步与线程同步 3.创建多线程应用程序 3.1通过System.Threading命名空间的类构建 3.1.1异步调用线程 3.1.2并发问题 3.1.3线程同步 3. ...
- java读写
IO流下分为字节流与字符流,每个流又分为输入输出以及读写. 字节流的两个基类为InputStream与OutputStream. 字符流为Reader和Writer
- 动态规划 最长公共子序列 LCS,最长单独递增子序列,最长公共子串
LCS:给出两个序列S1和S2,求出的这两个序列的最大公共部分S3就是就是S1和S2的最长公共子序列了.公共部分 必须是以相同的顺序出现,但是不必要是连续的. 选出最长公共子序列.对于长度为n的序列, ...