【混合】【二分】【最短路】二分最短路模型【CF】G.It is all about wisdom

Mixed——二分最短路模型——G.It is all about wisdom

考时bfs,dfs加剪枝(dfs在最坏情况下的剪枝相当于bfs加剪枝,其实bfs加剪枝,有点奇怪,一些剪枝在bfs的作用下并不能发挥很好的效果),在第二点的时候都t了,对于至少这类问题应该从二分的角度出发,而不是用求稳的思想,每一个点,每一条路都大概率地去尝试。(二分的check是有一定的原则去办事情,而普通的找是以相对弱的原则来办事情)

思路:二分是为了迅速找到一个值(智商值),如果能够以这个智商值过了就过了(最短路是为了尽可能压缩金钱的消耗,看一下最小花费会不会小于身上带的钱),并且还要尽可能逼近最优的智商值。

二分

  • 目的:为了从众多的可能的答案中快速找到最优答案,节省时间,如果有遇到time limited 的情况,可以考虑一下使用二分的写法

    换种角度来思考什么叫做可能的答案可能的答案,它的答案是一个范围,比如说至少,比如说至多,严格小于,less than.....

  • 二分的前提:单调性

  • 内容:

    • check函数

      (把最短路的算法融进来)

    • 边界的写法

bool check()
{
     if(条件) return true;
     return false;
}
  • 二分模板
while(l<=r)
{
    mid = l+(r-l)>>1;
    if(check(mid))
        r=r-1,ans=r;//趁机保留答案
    else l=l+1;
}

最短路

int dijkstra(int st,int ed,int 二分尝试的点)
{
      小根堆
      使用情况的使用数组
      将起点压入小根堆
      
      while(heap.size())
      {
           提取
           将提取出的结点的使用情况标记为已使用
           
           for 扫描提取出来的点的周围的所有边
               特殊情况 continue
               路径更不上时代 continue
               松弛操作
      }
      因为是二分,判断一下dist[ed]和二分尝试的点的关系,再看一下要return什么
}

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1E5+10,M = 2E5+10,INF = 0x3f3f3f3f;
typedef pair<int,int > PII;
int h[N],e[M],ne[M],w[M],limit[M],idx;
int n,m,cost;
void add(int a,int b,int c,int d)
{
	e[idx]=b,ne[idx]=h[a],w[idx]=c,limit[idx]=d,h[a]=idx++;
}
bool check(int x)
{
	int dist[n+1];//用dijkstra算法找到最小花费
	bool used[n+1]; 
	memset(dist,0x3f,sizeof(dist));
	memset(used,false,sizeof(used));
	priority_queue<PII,vector<PII>,greater<PII> > heap;
	heap.push(PII{0,1});

	while(heap.size())
	{
		PII t = heap.top();
		heap.pop();
		int d = t.first,u = t.second;
	    if(used[u])continue;
		used[u]=true; 
	
		for(int i=h[u];~i;i=ne[i])
		{
			int j = e[i];
			if(limit[i]>x||d+w[i]>cost)continue;//没有资格进入途径 
			if(dist[j]>d+w[i])
			{
                dist[j]=d+w[i];
				heap.push(PII(dist[j],j));
			}
		}
	}
	if(dist[n]<cost) return true;
	return false; 
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int l=0,r=0,mid;
		scanf("%d%d%d",&n,&m,&cost);
        
        memset(h,-1,sizeof(h));
        idx=0;//记得归零 
        
        for(int i=0;i<m;i++)
		{
		   	int aa,bb,mon,wis;
		   	cin>>aa>>bb>>mon>>wis;
		   	add(aa,bb,mon,wis);add(bb,aa,mon,wis);
		   	r=max(r,wis);
		}		

		int ans=-1;
		while(l<=r)
		{
			mid = l + (r-l)/2;
			if(check(mid))
			   ans=mid,r=mid-1;
			else l=mid+1;
		}
		cout<<ans<<endl;
	}
	return 0;
}

其他

  • 在使用链式前向星的写法的时候,不单要把h数组重新设置为-1,也要把idx归零在处理多组数据的时候).
  • 无向边记得乘2
原文地址:https://www.cnblogs.com/BeautifulWater/p/15106311.html