二分答案+spfa找正环
边权的确定:
因为(S1+S2+…+Si)/(T1+T2+…+Ti)=ans
所以S1-T1*ans+S2-T2*ans+S3-T3*ans+…+Si-Ti*ans=0
如果S1-T1*ans+S2-T2*ans+S3-T3*ans+…+Si-Ti*ans>0 ,则增加ans。
否则,减小ans。
作法:
首先二分ans,将边权设为Sn-Tn*ans。
然后通过spfa找正环,如果存在正环或者能够到达终点,增加ans。
否则,减小ans。
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int n;
const int maxn=105;
int P[maxn][maxn],T[maxn][maxn],c[maxn];
double l[maxn][maxn],dis[maxn];
bool vis[maxn];
queue<int>q;
bool spfa(int s)
{
memset(dis,-0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(c,0,sizeof(c));
while(!q.empty()) q.pop();
dis[s]=0;
q.push(s);
vis[s]=1;
while(!q.empty())
{
int x=q.front();
vis[x]=0;
q.pop();
for(int i=1;i<=n;i++)
{
if(dis[i]<dis[x]+l[x][i])
{
dis[i]=dis[x]+l[x][i];
if(!vis[i])
{
q.push(i);
vis[i]=1;
}
c[i]++;
if(c[i]>n) return 1;
}
}
}
if(dis[n]>0) return 1;
else return 0;
}
bool check(double mid)
{
memset(l,0,sizeof(l));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
l[i][j]=P[i][j]-mid*T[i][j];
if(spfa(1)) return 1;
else return 0;
}
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 mid,l=0,r=100000;
while(r-l>0.0001)
{
mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.3lf%",l);
return 0;
}
两月之后,已经忘记蒟蒻曾经做过这道题,于是快乐地打ci了 QAQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
蒟蒻丑陋代码(捂脸)
//double不要写成int啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
queue<double>q;
bool vis[10005];
double dis[10005],l[105][105];
int pass[10005],t[105][105],s[105][105];
int n;
double L,r,mid;
void makel(double mm)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
l[i][j]=s[i][j]-t[i][j]*mm;
}
}
bool check(double mm)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) dis[i]=-1e9+7;
memset(pass,0,sizeof(pass));
makel(mm);//建边
while(!q.empty()) q.pop();
q.push(1);
dis[1]=0;
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for(int i=1;i<=n;i++)
{
if(i==x) continue;
if(dis[i]<dis[x]+l[x][i])
{
dis[i]=dis[x]+l[x][i];
if(!vis[i])
{
q.push(i);
vis[i]=1;
}
pass[i]++;
if(pass[i]>=n) return true;
}
}
}
if(dis[n]>0) return true;
return false;
}
int main()//建边??邻接矩阵?? 哦行吧
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&s[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&t[i][j]);
}
L=0,r=10000.000;
while(r-L>0.00001)
{
mid=(r+L)/2;
if(check(mid)) L=mid;//<=
else r=mid;//>
}
printf("%.3lf",L);
return 0;
}