题目描述
题解
首先求出来n到1~n1的最短路,这个需要用到01分数规划
首先二分答案mid,那么假设
∑ai∑bi≤mid
,也就是当
∑ai−∑bi∗mid≤0
的时候说明还存在更优的答案
那么将每一条边的边权变成a-b*mid,然后spfa判断是否有负权的路径就行了
注意这里spfa只要有负权路就直接退出,会快很多
这样做n1次就求出了1~n1的答案
然后题目中都已经给你建好了两排点
对于一个空腔连着的两个点x,y,连边x->y,inf
然后对于奇数点,s->i,dis(i);对于偶数点,i->t,dis(t),其中dis即为上面求出来的答案
跑最小割就行了
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
const double eps=1e-3;
const double inf=1e9;
int dcmp(double x)
{
if (x<=eps&&x>=-eps) return 0;
return (x>0)?1:-1;
}
struct data{int x,y;double a,b;}e[100005];
int n,m,n1,m1,s,t;
double maxflow;
double dis[705];
namespace plan
{
int tot,point[705],nxt[100005],v[100005];double c[100005];
double dis[705];bool vis[705];
queue <int> q;
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void spfa(int id)
{
memset(dis,127,sizeof(dis));dis[n]=0;
memset(vis,0,sizeof(vis));vis[n]=1;
q.push(n);
while (!q.empty())
{
int now=q.front();q.pop();
vis[now]=0;
for (int i=point[now];i;i=nxt[i])
if (dcmp(dis[v[i]]-dis[now]-c[i])>0)
{
dis[v[i]]=dis[now]+c[i];
if (v[i]==id&&dcmp(dis[v[i]])<=0) return;
if (!vis[v[i]]) vis[v[i]]=1,q.push(v[i]);
}
}
}
bool check(int id,double mid)
{
for (int i=1;i<=m;++i) c[i]=e[i].a-e[i].b*mid;
spfa(id);
return dcmp(dis[id])<=0;
}
double find(int id)
{
double l=0,r=10,mid,ans=inf;
while (r-l>eps)
{
mid=(l+r)/2.0;
if (check(id,mid)) ans=r=mid;
else l=mid;
}
return ans;
}
}
namespace Flow
{
int tot,point[705],nxt[100005],v[100005];double remain[100005];
int deep[705],cur[705];
queue <int> q;
void init()
{
tot=-1;
memset(point,-1,sizeof(point));
}
void addedge(int x,int y,double cap)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
}
bool bfs(int s,int t)
{
for (int i=1;i<=t;++i) deep[i]=t;
deep[s]=0;
for (int i=1;i<=t;++i) cur[i]=point[i];
q.push(s);
while (!q.empty())
{
int now=q.front();q.pop();
for (int i=point[now];i!=-1;i=nxt[i])
if (deep[v[i]]==t&&dcmp(remain[i]))
{
deep[v[i]]=deep[now]+1;
q.push(v[i]);
}
}
return deep[t]<t;
}
double dfs(int now,int t,double limit)
{
if (now==t||!dcmp(limit)) return limit;
double flow=0,f;
for (int i=point[now];i!=-1;i=nxt[i])
{
cur[now]=i;
if (deep[v[i]]==deep[now]+1&&dcmp(f=dfs(v[i],t,min(remain[i],limit))))
{
flow+=f;
limit-=f;
remain[i]-=f;
remain[i^1]+=f;
if (!dcmp(limit)) break;
}
}
return flow;
}
void dinic(int s,int t)
{
while (bfs(s,t))
maxflow+=(dfs(s,t,inf));
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i)
{
scanf("%d%d%lf%lf",&e[i].x,&e[i].y,&e[i].a,&e[i].b);
plan::add(e[i].x,e[i].y);
}
scanf("%d%d",&m1,&n1);
for (int i=1;i<=n1;++i)
dis[i]=plan::find(i);
Flow::init();
s=n+1,t=s+1;
for (int i=1;i<=n1;++i)
{
if (i&1) Flow::addedge(s,i,dis[i]);
else Flow::addedge(i,t,dis[i]);
}
for (int i=1;i<=m1;++i)
{
int x,y;scanf("%d%d",&x,&y);
Flow::addedge(x,y,inf);
}
Flow::dinic(s,t);
if (maxflow>1e8) puts("-1");
else printf("%.1lf\n",maxflow);
}