题目描述
给出一张有N个点M条边的加权有向无环图,接下来有Q个询问,每个询问包括2个节点X和Y,要求算出从X到Y的一条路径,使得密度最小(密度的定义为,路径上边的权值和除以边的数量)。
输入输出格式
输入格式:第一行包括2个整数N和M。
以下M行,每行三个数字A、B、W,表示从A到B有一条权值为W的有向边。
再下一行有一个整数Q。
以下Q行,每行一个询问X和Y,如题意所诉。
输出格式:对于每个询问输出一行,表示该询问的最小密度路径的密度(保留3位小数),如果不存在这么一条路径输出“OMG!”(不含引号)。
输入输出样例
输入样例#1:
3 3 1 3 5 2 1 6 2 3 6 2 1 3 2 3
输出样例#1:
5.000 5.500
说明
1 ≤ N ≤ 10,1 ≤ M ≤ 100,1 ≤ W ≤ 1000,1 ≤ Q ≤ 1000
01分数规划裸题
首先考虑一下二分答案ans
如果有存在
ans > Σw[i] / cnt 即 Σ(w[i] - ans) / cnt < 0的情况
那么答案不合法,反之答案合法
然后spfa跑一跑就好了
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef double DL;
const int INF = 2147483647;
const int maxn = 100;
struct data{
int to,w;
DL v;
};
queue<int> Q;
vector<data> e[maxn];
int n,m;
DL dis[maxn];
bool exist[maxn],vis[maxn];
DL ans[maxn][maxn];
inline int getint()
{
int ret = 0,f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret * f;
}
inline bool spfa(int s,int t)
{
for (int i = 1; i <= n; i++) dis[i] = INF;
dis[s] = 0;
Q.push(s);
while (!Q.empty())
{
int u = Q.front();
exist[u] = 0;
Q.pop();
for (int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].to;
DL w = e[u][i].v;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if (!exist[v])
{
Q.push(v);
exist[v] = 1;
}
}
}
}
return dis[t] <= 0;
}
inline void rebuild(DL x)
{
for (int i = 1; i <= n; i++)
for (int j = 0; j < e[i].size(); j++)
e[i][j].v = (DL)(e[i][j].w) - x;
}
inline DL binary(int u,int v)
{
DL l = 0,r = 1000;
for (int i = 1; i <= 30; i++)
{
DL mid = (l + r) / 2;
rebuild(mid);
if (spfa(u,v))
r = mid;
else
l = mid;
}
return l;
}
inline bool dfs(int u,int t)
{
vis[u] = 1;
if (u == t) return 1;
for (int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].to;
if (vis[v]) continue;
if (dfs(v,t)) return 1;
}
return 0;
}
int main()
{
n = getint();
m = getint();
for (int i = 1; i <= m; i++)
{
int u = getint(),v = getint(),w = getint();
e[u].push_back((data){v,w});
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if (i == j) continue;
memset(vis,0,sizeof(vis));
if (!dfs(i,j)) {ans[i][j] = -1; continue;}
ans[i][j] = binary(i,j);
}
int q = getint();
for (int i = 1; i <= q; i++)
{
int u = getint(),v = getint();
if (ans[u][v] == -1) printf("OMG!\n");
else printf("%0.3lf\n",ans[u][v]);
}
return 0;
}