1. 程式人生 > 其它 >二分最短路模型——G.It is all about wisdom

二分最短路模型——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