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

    搜索

    提供一种不一样的做法。

    我在写这个题的时候刚刚学了二分和搜索 还不会最短路,就把这个题当做二分题写了。可能是数据比较水吧。首先看到最小值最大或者最大值最小,我们的第一直觉就是二分答案。

    我们二分最大值,我们只走那些小于等于二分的答案的路,如果我们能够走到终点,就说明我们设置的条件比较弱,我们就可以减小二分的答案,当我们走不到终点的时候,就说明我们二分的条件比较严,我们就应该调大我们二分的答案,一直这样下去我们就能找到一个比较精确的值,当这个条件精确到唯一的一个值的时候,我们就二分到了我们要的答案。

    二分答案很重要的就是check()函数了,很多大佬都是写的最短路(dijkstral/spfa),将掉血量看成路的长度,看看符合条件的掉血量是否符合条件,然后再调整mid值,继续二分。二分的复杂度为(O(log(n))),然后再乘上最短路的时间复杂度,就是整体的时间复杂度。但是我写这个题的时候还不会写最短路,之好写了搜索,但可能是数据比较水,被我水过了,当然,我后续会补上关于最短路的题解。

    以下就是我的早期代码,可能存在的问题比较多,倘若有什么问题,还望大家不吝赐教,指出我的错误。

    最后献上我丑陋的代码

    #include<iostream>
    #include<cstdio>
    using namespace std;
    struct bian
    {
    	int to,nt,dis;
    }e[100001];
    int f[10001],head[10001],tot,ans;
    bool flag=0;
    int n,m,b,x,y,z;
    void add(int from,int to,int dis)
    {
    	e[++tot].to=to;
    	e[tot].dis=dis;
    	e[tot].nt=head[from];
    	head[from]=tot;
    }
    void check(int fr,int l,int x,int q)
    {	
        if(f[1]>q||f[n]>q) {flag=0;return;}
        if(fr==n)          {flag=1;return;}
    	for(int i=head[fr];i;i=e[i].nt)
    	{
    		if(f[e[i].to]<=q&&x-e[i].dis>0&&e[i].to!=l)
    		{
    			check(e[i].to,fr,x-e[i].dis,q);	
    		}
    		if(flag==1)return;
    	}
    }
    int main()
    {
    	cin>>n>>m>>b;
    	for(int i=1;i<=n;++i)scanf("%d",&f[i]);
    	for(int i=1;i<=m;++i)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);add(y,x,z);
    	}
    	int l=0,r=2147483646;
    	check(1,0,b,2147483646);
    	if(flag==0)
    	{
    		cout<<"AFK";
    		return 0;
    	}
    	while(l<=r)
    	{
    		flag=0;
    		int mid=(l+r)>>1;
    		check(1,0,b,mid);
    		if(flag==1)
    		{
    			r=mid-1;
    			ans=mid;
    		}
    		else l=mid+1;
    	}
    	cout<<ans;
    	return 0;
    }
    

    update

    已经补上关于最短路的题解(SPFA)

    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<cstdio>
    using namespace std;
    const int N=10010;
    struct bian
    {
    	int to,nt,dis;
    }e[100001];
    int n,m,b,x,y,z,tot,ans;
    int f[N],head[N];
    long long dis[N];
    bool vis[N];
    void add(int from,int to,int dis)
    {
    	e[++tot].to=to;
    	e[tot].dis=dis;
    	e[tot].nt=head[from];
    	head[from]=tot;
    }
    bool check(int mid)
    {	
        if(f[1]>mid||f[n]>mid)return 0;
        memset(dis,0x3f,sizeof(dis));
    	queue<int>q;
    	q.push(1);
    	vis[1]=1;dis[1]=0;
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();vis[x]=0;
    		for(int i=head[x];i;i=e[i].nt)
    		{
    			if(f[e[i].to]>mid)continue;
    			if(dis[e[i].to]>dis[x]+e[i].dis)
    			{
    				dis[e[i].to]=dis[x]+e[i].dis;
    				if(!vis[e[i].to])
    				{
    					q.push(e[i].to);
    					vis[e[i].to]=1;
    				}
    			}
    		}
    	}
    	return dis[n]<b;
    }
    int main()
    {
    	cin>>n>>m>>b;
    	for(int i=1;i<=n;++i)scanf("%d",&f[i]);
    	for(int i=1;i<=m;++i)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);add(y,x,z);
    	}
    	int l=0,r=2147483646;
    	if(!check(2147483646))
    	{
    		cout<<"AFK";
    		return 0;
    	}
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid))
    		{
    			r=mid-1;
    			ans=mid;
    		}
    		else l=mid+1;
    	}
    	cout<<ans;
    	return 0;
    }
    

    效率高了一倍,珍爱生命,远离 乱搞

  • 相关阅读:
    堆栈
    一元多项式的乘法和加法
    单链表每隔k反转
    python命令行参数
    markdown学习笔记
    ansible学习笔记
    Linux进程管理和性能相关工具
    二分查找,折半查找,特殊情况二分查找
    插入排序,冒泡排序,归并排序, 稳定排序
    不稳定排序,选择排序,快速排序,快速排序优化, 内部排序
  • 原文地址:https://www.cnblogs.com/wljss/p/11536350.html
Copyright © 2011-2022 走看看