您的位置:首页 > 其它

CodeVS1183 泥泞的道路 解题报告【二分答案+SPFA最长路】

2017-10-22 19:15 459 查看
题目描述 Description

CS有n个小区,并且任意小区之间都有两条单向道路(a到b,b到a)相连。因为最近下了很多暴雨,很多道路都被淹了,不同的道路泥泞程度不同。小A经过对近期天气和地形的科学分析,绘出了每条道路能顺利通过的时间以及这条路的长度。

现在小A在小区1,他希望能够很顺利地到达目的地小区n,请帮助小明找出一条从小区1出发到达小区n的所有路线中(总路程/总时间)最大的路线。请你告诉他这个值。

输入描述 Input Description

第一行包含一个整数n,为小区数。

接下来n*n的矩阵P,其中第i行第j个数表示从小区i到小区j的道路长度为Pi,j。第i行第i个数的元素为0,其余保证为正整数。

接下来n*n的矩阵T,第i行第j个数表示从小区i到小区j需要的时间Ti,j。第i行第i个数的元素为0,其余保证为正整数。

输出描述 Output Description

写入一个实数S,为小区1到达n的最大答案,S精确到小数点后3位。

样例输入 Sample Input

3

0 8 7

9 0 10

5 7 0

0 7 6

6 0 6

6 2 0

样例输出 Sample Output

2.125

数据范围及提示 Data Size & Hint

【数据说明】

30%的数据,n<=20

100%的数据,n<=100,p,t<=10000

解题报告

题目要求一个最大的答案,那么我们考虑二分,显然这样的状态是合法的:

P1+P2+P3+...+PnT1+T2+T3+...+Tn>ans

我们把分母去掉,可以得到:

P1+P2+P3+...Pn>ans∗(T1+T2+T3+...+Tn)

移项可得:

P1−ans∗T1+P2−ans∗T2+P3−ans∗T3+...+Pn−ans∗Tn>0

考虑怎么在这样一个式子的基础上写check函数。

如果我们令一条边的边权为Pi−mid∗Ti,那么dis[n] 显然就存储了上述式子的值。而我们希望上面这个式子更大,因为这样就可以让ans更大,所以我们就跑最长路,判定dis[n]是否大于0就好了。

因为是最长路,还需要考虑正环的情况。因为正环可以让dis
无限大,所以正环一定是合法的。

最后这道题竟然不卡精度,eps=10−4就好了。

代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=100;
const double eps=1e-4;
int p[N+5][N+5],t[N+5][N+5];
double w[N+5][N+5],dis[N*N+5];
bool flag[N*N+5];
int tim[N*N+5],n;
int spfa(int s,int e)
{
queue<int>q;
memset(dis,-0x3f,sizeof(dis));
memset(flag,false,sizeof(flag));
memset(tim,0,sizeof(tim));
dis[s]=0,flag[s]=true,tim[s]++;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
flag[u]=false;
for(int v=1;v<=n;v++)
if(p[u][v]!=0&&dis[v]<dis[u]+w[u][v])
{
dis[v]=dis[u]+w[u][v];
if(!flag[v])
{
tim[v]++;
q.push(v);
flag[v]=true;
if(tim[v]>e)return true;
}
}
}
return dis[e]>0;
}
int check(double mid)
{
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)w[i][j]=p[i][j]-mid*t[i][j];
return spfa(1,n);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)scanf("%d",&p[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)scanf("%d",&t[i][j]);
double lf=0,rg=10000;
while(rg-lf>eps)
{
double mid=(lf+rg)/2.0;
if(check(mid))lf=mid;
else rg=mid;
}
printf("%.3lf",lf);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: