天天看点

P1730 最小密度路径-01分数规划题目大意题目分析代码

题目大意

题目链接

题目大意:一个有向无环图(DAG),边权均为正整数。

定义一条路径的密度为 路径上的边权和/边数。

先有q组询问,每次给出xy,求从x到y的若干条路径中的最小路径密度是多少。

题目分析

令c为边权,d为路径条数

那么所求即为: ∑ c d \frac{\sum{c}}{d} d∑c​

这是一个和式分式,对于这种题目,我们通常用一种方法叫做 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]);
	}
}
           

继续阅读