/*
思路:
用链式向前星存储顶点之间的关系与权值
用优先队列存储边权小的先出
首先将起点入队,向四周发散,再将起点与到达点的总权值入队,
保证了是一步一步到达(如果不连通不可能遍历到),同时遍历的过程当中不断找更小的权值并更新
优先队列的用处:若有两种不同的到达方式,优先队列会先遍历到短的那一条,然后将其入队,那远的一条就不会入队。
*/
#include
using namespace std;
const int N=5e5+10,M=2e5+10;
int n,m,s,x,y,z,cnt,vis[N],head[N];
long long dis[N];
struct edge
{
int w,to,next;
}e[N];
void add(int x,int y,int z)
{
e[++cnt].to=y;
e[cnt].w=z;
e[cnt].next=head[x];
head[x]=cnt;
}
struct node
{
int u,w;
};
bool operator < (const node &s1,const node &s2)//重载运算符,优先队列中的自定义排序
{return s1.w>s2.w;}//注意写大于号还是小于号与实际的符号相反,实际是小于号,则要写大于号
priority_queue<node>q;
void dij()
{
q.push({s,0});
dis[s]=0;
while(!q.empty())
{
int u=q.top().u;q.pop();
if(vis[u])continue;
vis[u]=1;
//遍历所有以u为起点的边
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
//dis[u]为起点到u的权值,e[i].w是u到v的权值,dis[v]是起点到v的权值
if(dis[u]+e[i].w<dis[v])
{
dis[v]=dis[u]+e[i].w;
q.push((node){v,dis[v]});
}
}
}
}
int main()
{
cin>>n>>m>>s;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&z);
add(x,y,z);
}
for(int i=0;i<=n;i++)
dis[i]=2147483647;
dij();
for(int i=1;i<=n;i++)
printf("%lld ",dis[i]);
return 0;
}
思路就是将最短路上的路径遍历一遍,都堵一次,找花费时间最大的。
/*
思路:
用链式向前星存储顶点之间的关系与权值
用优先队列存储边权小的先出
首先将起点入队,向四周发散,再将起点与到达点的总权值入队,
保证了是一步一步到达(如果不连通不可能遍历到),同时遍历的过程当中不断找更小的权值并更新
优先队列的用处:若有两种不同的到达方式,优先队列会先遍历到短的那一条,然后将其入队,那远的一条就不会入队。
*/
#include
using namespace std;
const int N=1e3+10,M=2e5+10;
int n,m,s,x,y,z,cnt,vis[N],head[N],st,ed,flag;
int dis[N],last[N];
struct edge
{
int w,to,next;
}e[N*N];
void add(int x,int y,int z)
{
e[++cnt].to=y;
e[cnt].w=z;
e[cnt].next=head[x];
head[x]=cnt;
}
struct node
{
int u,w;
};
bool operator < (const node &s1,const node &s2)//重载运算符,优先队列中的自定义排序
{return s1.w>s2.w;}//注意写大于号还是小于号与实际的符号相反,实际是小于号,则要写大于号
priority_queue<node>q;
void dij()
{
memset(vis,0,sizeof(vis));
for(int i=0;i<=n;i++)
dis[i]=2147483647;
q.push({s,0});
dis[s]=0;
while(!q.empty())
{
int u=q.top().u;q.pop();
if(vis[u])continue;
vis[u]=1;
//遍历所有以u为起点的边
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(u==st&&v==ed)continue;
//dis[u]为起点到u的权值,e[i].w是u到v的权值,dis[v]是起点到v的权值
if(dis[u]+e[i].w<dis[v])
{
if(!flag)last[v]=u;
dis[v]=dis[u]+e[i].w;
q.push((node){v,dis[v]});
}
}
}
}
int main()
{
cin>>n>>m;
s=1;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dij();
int ans=0;
ed=n;
flag=1;
while(ed!=1)
{
st=last[ed];
s=1;
dij();
ans=max(ans,dis[n]);
ed=st;
}
cout<<ans<<endl;
return 0;
}
题目的关键词“最大最小值”,一看就是二分的题,二分大小,满足即可右区间调左,不满足则左区间右移,第一次没做出来,日后复习再做。