P1730 最小密度路徑-01分數規劃

題目大意

題目鏈接

題目大意:一個有向無環圖(DAG),邊權均爲正整數。

定義一條路徑的密度爲 路徑上的邊權和/邊數。

先有q組詢問,每次給出xy,求從x到y的若干條路徑中的最小路徑密度是多少。

題目分析

令c爲邊權,d爲路徑條數

那麼所求即爲:cd\frac{\sum{c}}{d}

這是一個和式分式,對於這種題目,我們通常用一種方法叫做 01分數規劃

我們二分答案,然後判斷。

判斷過程:把每條邊邊權-二分答案然後判斷最短路的正負性。

如果最短路是負的那麼答案不合法,修改r

否則修改l

代碼

下附AC代碼

#include<bits/stdc++.h>
using namespace std;
int read(){
	char s;
	int x=0,f=1;
	s=getchar();
	while(s<'0'||s>'9'){
		if(s=='-')f=-1;
		s=getchar();
	}
	while(s>='0'&&s<='9'){
		x*=10;
		x+=s-'0';
		s=getchar();
	}
	return x*f;
}
const int N=55;
int n,m;
vector<int>v[N];
vector<double>v1[N];
double ans[N][N];
double dist[N];
bool in[N];
queue<int>q;
bool spfa(int s,int ask,double limit){
	for(int i=1;i<=n;i++){
		dist[i]=0x3f3f3f3f;
		in[i]=0;
	}
	dist[s]=0;
	q.push(s);
	in[s]=1;
	while(!q.empty()){
		int x=q.front();
		in[x]=0;
		q.pop();
		for(int i=0;i<v[x].size();i++){
			int k=v[x][i];
			if(dist[k]>dist[x]+v1[x][i]-limit){
				dist[k]=dist[x]+v1[x][i]-limit;
				if(!in[k]){
					in[k]=1;
					q.push(k);
				}
			}
		}
	}
	return dist[ask]>0;
}
double maxn;
void go(int x,int y){
	double l=0,r=maxn;
	spfa(x,y,0);
	if(dist[y]==0x3f3f3f3f){
		ans[x][y]=-1;
		return;
	}
	while(r-l>1e-6){
		double mid=(l+r)/2;
		if(spfa(x,y,mid))l=mid;
		else r=mid;
	}
	ans[x][y]=l;
	return;
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int a,b,c;
		a=read(),b=read(),c=read();
		maxn+=c;
		v[a].push_back(b);
		v1[a].push_back(c);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			go(i,j);
		}
	}
	int Q=read();
	for(int i=1;i<=Q;i++){
		int x=read(),y=read();
		if(ans[x][y]<0)printf("OMG!\n");
		else printf("%.3lf\n",ans[x][y]);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章