传送门:QAQ
题意:每个点都有兴趣值,每条边都有花费时间,让你找出一个环,环上的兴趣值和除以总时间和最大,问你最大的值是多少。
思路:很明显,只要你会01分数规划,你就会发现这个只是将check的变在了图上,所以我们列出式子∑Fi-ans∑Ti<=0.然后我们二分ans,然后将图中的边变为Fi-ans*Ti,这样我们只要判断图中是否有正环就可以判断这个式子是否成立,但是这样是不对的,如果我们式子列成这样的话,如果我们跑出一个正环,证明这个式子是正确的,但是我们无法跑出图中是否有正环(因为spfa有一个负环就判有负环),所以我们只要简单的将式子转变一下,ans∑Ti-∑Fi>=0.这样我们就可以用图中是否存在负环判断边界了。
因为它每个点都可以作为起点,所以我们在跑spfa时可以将所有的点都放进队列。
poj的double一定要用%f输出QAQ
附上代码:
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
double F[1100];
int n, m;
struct inst {
int from;
int to;
double w;
inst() {}
inst(int f, int t, double ww) {
this->from = f;
this->to = t;
this->w = ww;
}
};
struct Edge {
int v;
double w;
int next;
};
int head[1100];
Edge edge[11000];
int vis[1100];
int sum[1100];
double dis[1100];
int cnt;
vector<inst>G;
void addedge(int u, int v, double w) {
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
bool spfa() {
memset(vis, 0, sizeof(vis));
memset(sum, 0, sizeof(sum));
for (int i = 0; i <= n; i++) {
dis[i] = 0;
}
queue<int>q;
for (int i = 1; i <= n; i++) {
q.push(i);
}
while (!q.empty()) {
int p = q.front();
q.pop();
vis[p] = 0;
for (int u = head[p]; u != -1; u = edge[u].next) {
int to = edge[u].v;
if (dis[to] > dis[p] + edge[u].w) {
dis[to] = dis[p] + edge[u].w;
if (!vis[to]) {
sum[to]++;
vis[to] = 1;
q.push(to);
if (sum[to] >= n) return 1;
}
}
}
}
return 0;
}
bool check(double x) {
cnt = 0;
memset(head, -1, sizeof(head));
for (int i = 0; i < G.size(); i++) {
inst zz = G[i];
addedge(zz.from, zz.to, x * zz.w - F[zz.from]);
}
if (spfa()) return true;
return false;
}
int main(void) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lf", &F[i]);
}
for (int i = 0; i < m; i++) {
int a, b;
double c;
scanf("%d%d%lf", &a, &b, &c);
G.push_back(inst(a, b, c));
}
double left = 0;
double right = 100.0;
while (fabs(right - left) >= 1e-6) {
double mid = (right + left) / 2;
if (check(mid)) {
left = mid;
}
else {
right = mid;
}
}
printf("%.2f\n", left);
}