- 給你一個含有 個點 條有向邊的圖,每條邊有兩個值: 和 ,分別表示這條路的價值和花費。
- 一條路的收益定義爲所有邊的 值的和比上 值的和。
- 求一條沒有相同的邊的環,使得其收益最大。
二分答案。記當前二分出來的值爲 ,表示總收益 。
如果滿足,則:
於是,我們修改每條邊的邊權爲 即可,求負環即可。
注意,bfs spfa
求負環的時間複雜度爲 ,可能會超時,所以我們賭一把,用時間複雜度不穩定的 dfs spfa
。
const int M=20100,N=7010;
struct edge{//鏈式前向星
int next,to,v,p;
}e[(M<<1)+N];int h[N],tot,n,m;
void add(int a,int b,int c,int d){
e[++tot]=(edge){h[a],b,c,d};h[a]=tot;
}
bool vis[N];double dis[N],l,r,mid;
inline bool dfs(int u,double mid){
vis[u]=true;register int i;
for(i=h[u];i;i=e[i].next){
register int to=e[i].to;
double w=e[i].p*mid-e[i].v;
if (dis[to]>dis[u]+w){
dis[to]=dis[u]+w;
if (vis[to]) return true;
if (dfs(to,mid)) return true;
}
}
vis[u]=false;
return false;
}
inline bool check(double mid){
memset(dis,127,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[0]=0;//注意特別初始化dis[0]
return dfs(0,mid);//返回spfa結果
}
const double eps=1e-5;
int main(){
scanf("%d%d",&n,&m);//點數;邊數
for(int i=1,a,b,v,p;i<=m;i++){
scanf("%d%d%d%d",&a,&b,&v,&p);
add(a,b,v,p);//往圖中加邊
}
for(int i=1;i<=n;i++)
add(0,i,0,0);//超級源
l=0;r=200;//初始二分上下界
while (l+eps<r){//注意精度
mid=(l+r)/2;//求出中點
if (check(mid)) l=mid;
else r=mid;//修改邊界
}
if (l==0) printf("-1");
else printf("%.1lf",l);
return 0;
}