hdu1839(二分+优先队列,bfs+优先队列与spfa的区别)
题意:有n个点,标号为点1到点n,每条路有两个属性,一个是经过经过这条路要的时间,一个是这条可以承受的容量。现在给出n个点,m条边,时间t;需要求在时间t的范围内,从点1到点n可以承受的最大容量........
思路:其实我是觉得思路挺简单的,就是二分枚举每条边的容量,然后再看在这个容量的限制下,是否可以从点1到点n........
方法1:二分枚举边的容量,然后一次dfs,判断在容量和时间的双重限制下,是否可以从点1到达点n......
wa代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
typedef __int64 ss;
struct node
{
ss k;
ss t;
ss v;
};
ss n,m,t,a[50005],sum,flag;
vector<node>vet[10005];
ss vist[10005];
void dfs(ss x,ss maxn,ss total)
{
if(x==n)
{
flag=1;
return;
}
if(flag==1)
return;
for(ss i=0;i<vet[x].size();i++)
{
node p=vet[x][i];
if(!vist[p.k]&&p.v>=maxn&&(p.t+total<=t))
{
vist[p.k]=1;
dfs(p.k,maxn,p.t+total);
}
}
}
ss deal(ss num)
{
ss maxn=a[num];
flag=0;
memset(vist,0,sizeof(vist));
dfs(1,maxn,0);
return flag;
}
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
ss cnt=0;
scanf("%I64d%I64d%I64d",&n,&m,&t);
for(int i=0;i<=n;i++)
vet[i].clear();
for(ss i=0;i<m;i++)
{
ss v1,v2,tmp,tmp1;
scanf("%I64d %I64d %I64d %I64d",&v1,&v2,&tmp,&tmp1);
node p;
p.k=v2;
p.t=tmp1;
p.v=tmp;
vet[v1].push_back(p);
p.k=v1;
vet[v2].push_back(p);
a[cnt++]=tmp;
}
sort(a,a+cnt);
//printf("%I64d\n",cnt);
ss ll=0,rr=cnt-1;
ss ans=0;
while(ll<=rr)
{
sum=0;
ss mid=(ll+rr)/2;
if(deal(mid))
{
if(ans<a[mid])
ans=a[mid];
ll=mid+1;
}
else rr=mid-1;
}
printf("%I64d\n",ans);
}
return 0;
}
我倒是很快明白了过来,错误在什么地方。因为我的dfs是每个点只历遍一次,有的路被忽略掉了,从而导致wa,额,可以改改,让dfs回溯,然后重置vist标记数组,但是这样做的话,肯定超时...<..>
方法2:二分枚举边的容量,然后用优先队列+bfs,判断在容量和时间的双重限制下,是否可以从点1到达点n......
wa代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
typedef __int64 ss;
struct node
{
ss k;
ss t;
ss v;
};
struct node1
{
friend bool operator<(const node1 a,const node1 b)
{
if(a.t>b.t)
return 1;
else
return 0;
}
ss e;
ss t;
}; ss n,m,t,a[500005],sum,flag;
vector<node>vet[100005];
ss vist[100005];
/*void dfs(ss x,ss maxn,ss total)
{
if(x==n)
{
flag=1;
return;
}
if(flag==1)
return;
for(ss i=0;i<vet[x].size();i++)
{
node p=vet[x][i];
if(!vist[p.k]&&p.v>=maxn&&(p.t+total<=t))
{
vist[p.k]=1;
dfs(p.k,maxn,p.t+total);
vist[p.k]=0;
}
}
}*/
priority_queue<node1>q;
ss bfs(ss num)
{
ss minx=a[num];
node1 p;
memset(vist,0,sizeof(vist));
p.e=1;
p.t=0;
while(!q.empty())
q.pop();
q.push(p);
vist[p.e]=1;
while(!q.empty())
{
p=q.top();
q.pop();
vist[p.e]=0;
if(p.e==n)
{
if(p.t<=t)
{
return 1;
}
return 0;
}
ss x=p.e;
for(ss i=0; i<vet[x].size(); i++)
{
node p1=vet[x][i];
node1 iter;
iter.e=p1.k;
iter.t=p1.t+p.t;
if(!vist[p1.k]&&p1.v>=minx&&iter.t<=t)
{
vist[p1.k]=1;
q.push(iter);
}
}
}
return 0;
}
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
ss cnt=0;
scanf("%I64d%I64d%I64d",&n,&m,&t);
for(ss i=0; i<=n; i++)
vet[i].clear();
for(ss i=0; i<m; i++)
{
ss v1,v2,tmp,tmp1;
scanf("%I64d %I64d %I64d %I64d",&v1,&v2,&tmp,&tmp1);
node p;
p.k=v2;
p.t=tmp1;
p.v=tmp;
vet[v1].push_back(p);
p.k=v1;
vet[v2].push_back(p);
a[cnt++]=tmp;
}
sort(a,a+cnt);
//printf("%I64d\n",cnt);
ss ll=0,rr=cnt-1;
ss ans=0;
while(ll<=rr)
{
//sum=0;
ss mid=(ll+rr)/2;
if(bfs(mid))
{
if(ans<a[mid])
ans=a[mid];
ll=mid+1;
}
else rr=mid-1;
}
printf("%I64d\n",ans);
}
return 0;
}
思考了很久,也是明白了为什么会wa。在以往,我使用bfs、bfs+优先队列求最小值、最短路什么的时候,都是在一张点图上求解的。换句话说,那样的图上,一个点到另一个点可以到达,那么它们必然相邻,然后路径值固定是1,当然也许会有从某个点到另一个点,路径不是1的,假设从这个点到那个点的距离是k,那么从其他相邻点到那个点的距离也是k,如此就可以使得bfs搜索过去的每个状态只需更新一次,因为更新完一次必然是最小的。
但是,这个题目却是不同。因为它并不是点有权值,而是边的权值,假如我从点1到点3这个点权值为9,那么从点2到点3的权值可以为3......如此就会导致搜索过去,更新了的状态并不是最小的........
这就是bfs与spfa的区别吧,bfs可以实现的时候,必然是点自身带权值,比如说,点1有两个属性,一个是xx,一个是yy,要是从其他可以到达点1的点,那么必须加上这个点的某个权值,然后求最小值........
而spfa却是边带权值.........
方法3:二分+spfa
ac代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
typedef __int64 ss;
struct node
{
ss k;
ss t;
ss v;
};
ss n,m,t,a[50005],sum,flag;
vector<node>vet[10005];
ss vist[10005],dis[10005];
ss spfa(ss num)
{
ss minx=a[num];
for(ss i=0; i<=n; i++)
{
dis[i]=((ss)1<<25);
vist[i]=0;
}
dis[1]=0;
vist[1]=1;
queue<ss>q;
q.push(1);
while(!q.empty())
{
ss x=q.front();
q.pop();
vist[x]=0;
for(ss i=0; i<vet[x].size(); i++)
{
node p=vet[x][i];
if(p.v>=minx)
{
if(dis[p.k]>dis[x]+p.t)
{
dis[p.k]=dis[x]+p.t;
if(!vist[p.k])
q.push(p.k);
vist[p.k]=1;
} }
}
}
if(dis[n]<=t)
return 1;
else return 0;
}
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
ss cnt=0;
scanf("%I64d%I64d%I64d",&n,&m,&t);
for(ss i=0; i<=n; i++)
vet[i].clear();
for(ss i=0; i<m; i++)
{
ss v1,v2,tmp,tmp1;
scanf("%I64d %I64d %I64d %I64d",&v1,&v2,&tmp,&tmp1);
node p;
p.k=v2;
p.t=tmp1;
p.v=tmp;
vet[v1].push_back(p);
p.k=v1;
vet[v2].push_back(p);
a[cnt++]=tmp;
}
sort(a,a+cnt);
//printf("%I64d\n",cnt);
ss ll=0,rr=cnt-1;
ss ans=0;
while(ll<=rr)
{
//sum=0;
ss mid=(ll+rr)/2;
if(spfa(mid))
{
if(ans<a[mid])
ans=a[mid];
ll=mid+1;
}
else rr=mid-1;
}
printf("%I64d\n",ans);
}
return 0;
}
hdu1839(二分+优先队列,bfs+优先队列与spfa的区别)的更多相关文章
- POJ 1724 ROADS(BFS+优先队列)
题目链接 题意 : 求从1城市到n城市的最短路.但是每条路有两个属性,一个是路长,一个是花费.要求在花费为K内,找到最短路. 思路 :这个题好像有很多种做法,我用了BFS+优先队列.崔老师真是千年不变 ...
- hdu 1026 Ignatius and the Princess I【优先队列+BFS】
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1026 http://acm.hust.edu.cn/vjudge/contest/view.action ...
- ZOJ 649 Rescue(优先队列+bfs)
Rescue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 【POJ3635】Full Tank 优先队列BFS
普通BFS:每个状态只访问一次,第一次入队时即为该状态对应的最优解. 优先队列BFS:每个状态可能被更新多次,入队多次,但是只会扩展一次,每次出队时即为改状态对应的最优解. 且对于优先队列BFS来说, ...
- hdu 1242 找到朋友最短的时间 (BFS+优先队列)
找到朋友的最短时间 Sample Input7 8#.#####. //#不能走 a起点 x守卫 r朋友#.a#..r. //r可能不止一个#..#x.....#..#.##...##...#.... ...
- Codeforces 677D - Vanya and Treasure - [DP+优先队列BFS]
题目链接:http://codeforces.com/problemset/problem/677/D 题意: 有 $n \times m$ 的网格,每个网格上有一个棋子,棋子种类为 $t[i][j] ...
- POJ 2449 - Remmarguts' Date - [第k短路模板题][优先队列BFS]
题目链接:http://poj.org/problem?id=2449 Time Limit: 4000MS Memory Limit: 65536K Description "Good m ...
- HDU 1428 漫步校园 (BFS+优先队列+记忆化搜索)
题目地址:HDU 1428 先用BFS+优先队列求出全部点到机房的最短距离.然后用记忆化搜索去搜. 代码例如以下: #include <iostream> #include <str ...
- BFS+优先队列+状态压缩DP+TSP
http://acm.hdu.edu.cn/showproblem.php?pid=4568 Hunter Time Limit: 2000/1000 MS (Java/Others) Memo ...
随机推荐
- Windbg使用方法
hgy413的专栏 http://blog.csdn.net/hgy413/article/category/1143065
- mac 终端添加颜色
1.打开终端,然后找到终端偏好设置,选择自己喜欢的颜色 2.然后切换到当前用户的家目录: cd ~ 3.打开文件,开始编辑".bash_profile", 添加下面两句 expor ...
- React(0.13) 组件的组合使用
<html> <head> <title>组件的组合调用</title> <script src="build_0.13/react.m ...
- 【Spring】Spring之依赖注入(DI)传递参数的方式
DI依赖注入传入参数的方式,这里介绍了基本数据类型,集合,符合数据类型的传递(String类型比较特殊,其传递值和基本数据类型的方法一致) 注入基本数据类型和String类型 通过setter方法注入 ...
- 通过Stetho在Chrome上调试Android App
引 入依赖包 compile 'com.facebook.stetho:stetho:1.3.1' 初始化一下 public class MyApplication extends Applicati ...
- JSP内置对象之WEB安全性及config对象
一.WEB-INF的安全性是最高的. 在Java EE的标准中,Web目录中的WEB-INF是必须存在的,而且此文件夹的安全性是最高的,在各个程序的开发中,基本上都将一些配置信息保存在此文件夹中.在定 ...
- 实现一个简单的android开关
近期在学习android中的graphics中绘图系列.依照大神思路.找葫芦画瓢实现了一个开关.如图下: 记录一下实现方式: 1.画背景 上图形状.分成两个半圆与一个矩形,那么代码能够写成: priv ...
- 利用AutoSPSourceBuilder和Autospinstaller自动安装SharePoint Server 2013图解教程——Part 1
这是一篇对之前 <利用AutoSPSourceBuilder和Autospinstaller自动安装SharePoint Server 2013图解教程——Part 2>的补充.本篇博客将 ...
- android开发之interpolator的使用
android:interpolator Interpolator 被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repea ...
- 关于easyui combobox下拉框实现多选框的实现
好长时间没有更博了,一是因为最近真的比较忙,二是因为自己是真的偷懒了,哈哈 好啦,这篇博客主要是总结一些关于easyui combobox下拉框实现多选框的实现,包括前台界面的展示,和后台对数据的获取 ...