报告错误
如果你发现该网页中存在错误/显示异常,可以从以下两种方式向我们报告错误,我们会尽快修复:
- 使用 CS Club 网站错误 为主题,附上错误截图或描述及网址后发送邮件到 286988023@qq.com
- 在我们的网站代码仓库中创建一个 issue 并在 issue 中描述问题 点击链接前往Github仓库
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)$