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: ...
随机推荐
- The Power of Reading——英语学习小技巧之七
This method is "The Power of Reading" and it comes from an article by Dr.Stephen Krashen. ...
- poj 2661 Factstone Benchmark
/** 大意: 求m!用2进制表示有多少位 m! = 2^n 两边同时取对数 log2(m!) = n 即 log2(1) + log2(2)+log2(3)+log2(4)...+log2(m) = ...
- Django内置template标签
html过滤{% autoescape on|off %} {{body}} {% endautoescape %} 注释{% comment %} {% endcomment %} csrf攻击 { ...
- 深入select_related与prefetch_related函数
阅读博客http://blog.jobbole.com/74881/的笔记 在数据库有外键的时候,使用select_related()和prefetch_related()可以很好的减少数据库请求的次 ...
- struts文件上传和下载
文件上传 jsp中 <a href="/file/new.action">文件上传案例</a> fileaction中 @Override public S ...
- Windows Phone 8初学者开发—第7部分:本地化应用程序
原文 Windows Phone 8初学者开发—第7部分:本地化应用程序 第7部分:本地化应用程序 原文地址: http://channel9.msdn.com/Series/Windows-Phon ...
- UNIX 缩写风格
构建于图形界面之上的操作系统,使用鼠标作为主输入设备, 是否使用缩写并不重要.比如 Windows 系统中的目录,几乎都是全称…… 点击两次鼠标进入文件夹 pf, 并不意味着点击13次才能进入文件夹 ...
- 【UVA】658 - It's not a Bug, it's a Feature!(隐式图 + 位运算)
这题直接隐式图 + 位运算暴力搜出来的,2.5s险过,不是正法,做完这题做的最大收获就是学会了一些位运算的处理方式. 1.将s中二进制第k位变成0的处理方式: s = s & (~(1 < ...
- 关于方法的ref
没有ref的方法时: using System; using System.Collections.Generic; using System.Linq; using System.Text; usi ...
- c++中的 堆和栈
/*用指针p存储堆中的空间时,在将第二块内存空间赋给p之前,我们要释放p原来指向的内存空间, 这样才不会造成内存泄漏,不然的话p原来记录的内存空间就找不到了,而且也无法再次利用 注意:你在使用new以 ...