1. 程式人生 > 實用技巧 >Rinne Loves Dynamic Graph(牛客演算法週週練16)

Rinne Loves Dynamic Graph(牛客演算法週週練16)

Rinne Loves Dynamic Graph(牛客演算法週週練16)

Problem:

Rinne 學到了一個新的奇妙的東西叫做動態圖,這裡的動態圖的定義是邊權可以隨著操作而變動的圖。
當我們在這個圖上經過一條邊的時候,這個圖上所有邊的邊權都會發生變動。

定義變動函式 \(f(x) = \frac{1}{1-x}\),表示我們在圖上走過一條邊後,圖的邊權變動情況。

這裡指的“圖的變動”的意思是將每條邊的邊權代入上函式,得到的值即為該次變動後的邊權。

現在 Rinne 想要知道,在這個變動的圖上從 1 到 n 的最短路徑。
因為 Rinne 不喜歡負數,所以她只需要你輸出經過的邊權權值絕對值之和最小的那個值就可以了。
輸出答案保留三位小數。

Input:

第一行兩個正整數 N,M,表示這個動態圖的點數和邊數。
接下來 M 行,每行三個正整數 u,v,w,表示存在一條連線點 u,v 的無向邊,且初始權值為 w。

Output:

如果能到達的話,輸出邊權絕對值之和最小的答案,保留三位小數。
否則請輸出 -1。

Example:

Input:

3 3
1 2 2
2 3 2
3 1 3

Output:

3.000

Note:

\(1 \to 2 \to 3\),總花費 \(2 + |\frac{1}{1-2}| = 3\)

Remark:

n≤100000,m≤300000,2≤x≤1000

題解:

最短路DP,分析邊權的變化公式可知:

\[f(x)=\frac{1}{1-x}\\f(f(x))=1-\frac{1}{x}\\f(f(f(x)))=x \]

所以,對於邊權的值根據已走過的邊數存在三種情況:

\[edge\ mod\ 3==1\to \frac{1}{1-x}\\edge\ mod\ 3==2\to 1-\frac{1}{x}\\edge\ mod\ 3==0\to x \]

Dijkstra計算最短路,記錄走過邊數,計算邊權代入計算最小值。

Code:

/**********************************************************
* @Author: 			   Kirito
* @Date:   			   2020-06-24 21:11:15
* @Last Modified by:   Kirito
* @Last Modified time: 2020-07-23 15:36:56
* @Remark: 
**********************************************************/
#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define CSE(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define Abs(x) (x>=0?x:(-x))
#define FAST ios::sync_with_stdio(false);cin.tie(0);
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll , ll> pll;

struct node
{
	int id,x;
	double dis;
	bool operator < (const node &b) const{
		return dis>b.dis;
	}
};

const int maxn=611111;
//graph
int first[maxn],nxt[maxn],u[maxn],v[maxn],w[maxn];
int n,m,cnt;
//dij
double dis[maxn][5];
int book[maxn][5];
//link-form
void add(int x,int y,int d)
{
	cnt++;
	u[cnt]=x;v[cnt]=y;w[cnt]=d;
	nxt[cnt]=first[u[cnt]];first[u[cnt]]=cnt;
	return;
}
//INi
void ini()
{
	for(int i=0;i<=n;i++){
		dis[i][0]=dis[i][1]=dis[i][2]=1e30;
	}
	return;
}
//getdis
double getdis(int nm,int w)
{
	switch(nm)
	{
		case 0: return fabs(1.0*w);
		case 1: return fabs(1.0/(1.0-w));
		case 2: return fabs(1.0-1.0/w);
	}
	return fabs(1.0*w);
}
//Dijkstra
void dijkstra()
{
	ini();CSE(book,0);
	priority_queue<node> box;
	box.push(node{0,1,0});dis[1][0]=0;
	while(!box.empty())
	{
		int x=box.top().x,t=box.top().id;;box.pop();
		if(book[x][t]) continue;
		book[x][t]=1;
		for(int i=first[x];i!=-1;i=nxt[i]){
			int y=v[i];
			int t2=(t+1)%3;
			double d=getdis(t,w[i])+dis[x][t];
			if(book[y][t2]) continue;
			if(dis[y][t2]>d){
				dis[y][t2]=d;
				box.push(node{t2,y,dis[y][t2]});
			}
		}
	}
	return;
}


int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	#endif
	CSE(first,-1);CSE(nxt,-1);cnt=0;
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	dijkstra();
	double ans=min(dis[n][0],min(dis[n][1],dis[n][2]));
	int k=(book[n][0]|book[n][1]|book[n][2]);
	if(k)
		printf("%.3lf\n",ans);
	else
		printf("-1\n");
	return 0;
}