zoukankan      html  css  js  c++  java
  • P1462 通往奥格瑞玛的道路 题解

    题目传送门

    1.题外话

    最近在刷有关图论,dp的题单~

    2.解题意

    n个节点,m条双向边。每个节点有一个权值(f[i]),每个边有一个边权((edge[i].dis)),起点编号是1,终点编号是n。让你求对于每一个b,使得(1到n)的最短路小于边权和小于等于b且使得路径上经过的最大的点权最小。

    3.找思路

    很明显,对于“最大值最小”(or)“最小值最大”的问题,考虑二分;

    我们二分枚举一个节点限制(now),点权f大于now的点不会考虑进路径,剩下的节点跑一遍最短路;

    如果到终点的最短路的dis数组,也就是最小边权和小于now,说明当前的这条路径减少的血量小于当前二分的血量,存在着最多的一次收取的费用的最小值更大的可能,我们就尝试使(r=mid-1),将now值缩小,继续二分下去。直到我们的l和r相差为1或者0.说明我们找到了那个最小的满足条件的点权和。输出即可。

    对于二分的题目,一定要明确自己要二分得到的结果,并且要清楚地知道边界情况的处理方式。如果想错了可能你的样例跑出来是对的,但是其他的一些数据会出锅。

    4.(Code)

    在这里用的是spfa。也可以用dij

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define ll long long
    #define re register
    #define N 10007
    #define inf 2147483646
    using namespace std;
    inline int read()
    {
    	int x=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    int n,m,b,num,hea[N],d[N],vis[N],f[N];
    int u,v,w;
    struct edg{
    	int next,to,dis;
    }edge[N*20];
    inline void add(int from,int to,int dis)
    {
    	num++;
    	edge[num].dis=dis;
    	edge[num].to=to;
    	edge[num].next=hea[from];
    	hea[from]=num;
    }
    inline bool spfa(int now)
    {
    	if(now<f[1])return 0;
    	queue<int> q;
    	for(int i=1;i<=n;i++)
    		d[i]=1e9;
    	memset(vis,0,sizeof(vis));
    	vis[1]=1;
    	d[1]=0;
    	q.push(1);
    	while(!q.empty())
    	{
    		int k=q.front();q.pop();
    		vis[k]=0;
    		for(int i=hea[k];i;i=edge[i].next)
    		{
    			int v=edge[i].to;
    			if(d[v]>d[k]+edge[i].dis&&f[v]<=now)
    			{
    				d[v]=d[k]+edge[i].dis;
    				if(!vis[v])
    				{
    					vis[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    	if(d[n]<b)return 1;
    	return 0;
    }
    int main()
    {
    	n=read(),m=read(),b=read();
    	for(int i=1;i<=n;i++)
    		f[i]=read();
    	for(int i=1;i<=m;i++)
    	{
    		u=read(),v=read(),w=read();
    		add(u,v,w),add(v,u,w);
    	}
    	int l=1,r=1e9+1;
    	if(!spfa(r))
    	{
    		printf("AFK
    ");
    		return 0;
    	}
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(spfa(mid))
    			r=mid-1;
    		else l=mid+1;
    	}
    	printf("%d",l);
    	return 0;
    }
    
    

    完结撒花。有问题可以在评论区指出。

  • 相关阅读:
    爬取豆瓣分页照片下载
    css布局:三列布局,中间内容优先加载
    解决在IE下label中IMG图片无法选中radio的几个方法
    CSS架构:最新最佳实践
    JavaScript登陆弹窗,可拖拽
    网站变成灰色的代码
    5个jQuery的备选轻量级移动客户端开发(Mobile development)类库
    jQuery 底部漂浮导航当前位置突出 + 锚点平滑滚动
    Exchange 2007 自定义传输规则
    基于jQuery打造TabPanel
  • 原文地址:https://www.cnblogs.com/lbssxz/p/13236712.html
Copyright © 2011-2022 走看看