目录

USACO 2019 Dec Gold P1

USACO analysis

李若谷 | 14 Apr 2021

USACO 2019 December Gold P1

题目大意

一个n个点m条双向边的图,每条边有花费$c$以及价值$f$,求从1到n中某一条道使得$\frac{min(f_i)}{\Sigma c}最大$

思路

可以固定$\min f_i$的值,然后显然$\Sigma c$越小,答案值越大。 所以可以直接枚举$\min f_i$,然后跑dijikstra

代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;
const int N = 1005,M = 2050;
int dist[N];
bool vis[N];
int n,m;
struct Edge{
	int to;
	int dis;
	int f;
	int next;
}edge[M];
struct Vertex{
	int dis;
	int v;
	bool operator < (const Vertex &x)const{
		return x.dis < dis;
	}
};
int head[N];
int cnt = 0;
void add_edge(int x,int y,int dis,int f){
	edge[++cnt].to = y;
	edge[cnt].next = head[x];
	edge[cnt].dis = dis;
	edge[cnt].f = f;
	head[x] = cnt;
}
int dij(int lb)
{
	priority_queue <Vertex> q;
	memset(vis,0,sizeof(vis));
	memset(dist,0x3f,sizeof(dist));
	dist[1] = 0;
	q.push((Vertex){0,1});
	while(!q.empty())
	{
		Vertex top = q.top();
		q.pop();
		if(vis[top.v]) continue;
		vis[top.v] = 1;
		for(int i = head[top.v];i;i=edge[i].next){
			int y = edge[i].to;
			if(edge[i].f<lb) continue;
			if(dist[y] > dist[top.v] + edge[i].dis)
			{
				dist[y] = dist[top.v] + edge[i].dis;
				q.push((Vertex){dist[y],y});
			}
		}
	}
	return dist[n];
}
int main()
{
	int ans = -1;
	int maxx = -1;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y,dis,f;
		cin>>x>>y>>dis>>f;
		add_edge(x,y,dis,f);
		add_edge(y,x,dis,f);
		maxx = max(maxx,f);
	}
	for(int i=1;i<=maxx;i++)
	{
		ans = max(ans,(int)1e6*i/dij(i));
	}
	cout<<ans<<endl;
	return 0;
}

时间复杂度

$O(\max( f_i)m\log m)$


评论区