您的位置:首页 > 其它

[BZOJ]3597: [Scoi2014]方伯伯运椰子 01分数规划+spfa

2017-09-27 14:51 447 查看
Description



题解:

对于一条边,我们这样建图:若c>0,u->v建权值为a-d的边,代表缩容量;v->u建权值为b+d的边,代表扩容量。我们要求(X-Y)/k的最大值,也就是(X-Y)/k>=ans,要求ans最大,我们二分这个ans,然后每条边权加上这个ans,若能跑出负环,则代表k×ans+Y-X<=0,也就是说当前答案是可行的。也可以这样理解,如果有负环证明我们有一种方案是可以使费用变小的。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int Maxn=5010;
const int Maxm=3010;
int n,m,u[Maxn],v[Maxn],c[Maxn];
double f[Maxn],a[Maxn],b[Maxn],d[Maxn];
struct Edge{int y,next;double d;}e[Maxm*2];
int last[Maxn],len=0;
bool in[Maxn],tf;
void ins(int x,int y,double d)
{
int t=++len;
e[t].y=y;e[t].d=d;
e[t].next=last[x];last[x]=t;
}
void spfa(int x,double ans)
{
in[x]=true;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;double d=e[i].d+ans;
if(f[x]+d<f[y])
{
if(!in[y])
{
f[y]=f[x]+d;
spfa(y,ans);
}
else{tf=true;return;}
}
}
in[x]=false;
}
bool check(double ans)
{
memset(in,false,sizeof(in));
memset(f,0,sizeof(f));
tf=false;
for(int i=1;i<=n;i++)
{
spfa(i,ans);
if(tf)return true;
}return false;
}
int main()
{
scanf("%d%d",&n,&m);n+=2;
for(int i=1;i<=m;i++)
{
scanf("%d%d%lf%lf%d%lf",&u[i],&v[i],&a[i],&b[i],&c[i],&d[i]);
if(c[i])ins(u[i],v[i],a[i]-d[i]);
ins(v[i],u[i],b[i]+d[i]);
}
double l=0.0,r=1e10;
int c=60;
while(c--)
{
double mid=(l+r)/2.0;
if(check(mid))l=mid;
else r=mid;
}
printf("%.2lf",l);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: