您的位置:首页 > 其它

[WIKIOI1183]泥泞的道路[二分答案+SPFA]

2014-03-01 13:36 302 查看
http://www.wikioi.com/problem/1183/

分析一下其实很简单的,转换成图论就可以做了。

这个题目是满足二分答案的性质的,因为对于一个答案a,如果a可以,那么比a小的必然也可以。

所以我们先用二分答案去枚举

但是这个二分答案需要注意精度问题,具体是什么呢?

一般二分答案是while(l <= r) if(check(mid)) l = mid + 1; else r = mid - 1;

这样的,愚蠢的我一开始就这样写了,然后精度错误balalalala的

cheeck怎么写呢,有一个p[i]是路程,对于答案ans

满足 你走的路程 / 耗费的时间 = ans

然后就可以根据这个等式去构图,以p[i][j] - t[i][j] * ans为边权,然后求最长路,如果有环这个ans肯定合法,如果没环但是dist
>=0 也合法

接下来贴代码

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cmath>
#include <iostream>
#define mod 9999973
#define inf 10000000
#define N 105
using namespace std;
int n , p

, t

, num
;
bool inq
;
double map

, d
, sum , sum1;
queue <int> q;
bool check(double ans)
{
//构图
memset(map , 0 , sizeof(map));
memset(inq , 0 , sizeof(inq));
while(!q.empty()) q.pop();
for(int i = 1 ; i <= n ; ++i) d[i] = (double)-1e8 , num[i] = 0;
for(int i = 1 ; i <= n ; ++i)
for(int j = 1 ; j <= n ; ++j)
{
if(i == j) continue;
map[i][j] = (double)p[i][j] - (double)t[i][j] * ans;
}
q.push(1) , inq[1] = 1;
d[1] = 0 , ++num[1];
while(!q.empty())
{
int po = q.front(); q.pop();
inq[po] = 0;
if(num[po] > n)
{
d
= 1e8; break;
}
for(int i = 1 ; i <= n ; ++i)
{
if(po == i) continue;
if(d[i] < d[po] + map[po][i])
{
d[i] = d[po] + map[po][i];
if(!inq[i]) q.push(i) , inq[i] = 1 , ++num[i];
}
}
}
if(d
>= 0) return 1;
return 0;
}
void work()
{
scanf("%d", &n);
double l = 0 , r = 0 , mid;
for(int i = 1 ; i <= n ; ++i) for(int j = 1 ; j <= n ; ++j) scanf("%d", &p[i][j]) , sum += p[i][j];
for(int i = 1 ; i <= n ; ++i) for(int j = 1 ; j <= n ; ++j)
{
scanf("%d", &t[i][j]) , sum1 += t[i][j];
if(p[i][j]) r = max(r , (double)p[i][j] / (double)t[i][j]);
}
l = sum / sum1;
mid = (l + r) / 2;
while(1)
{
if(r - l <= 0.00001) {printf("%.3lf" , mid); break;}
if(check(mid)) l = mid; else r = mid;
mid = (l + r) / 2;
}
}
int main()
{
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: