题解:
求比值用分数规划,单个求太慢了套整体二分
然后求二分图最小割
// luogu-judger-enable-o2 #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<cmath> using namespace std; const double eps=1e-10; const int maxn=1000; const int oo=1000000000; int n,m; int n1,m1; double val[maxn]; int dcmp(double x){ if(fabs(x)<eps)return 0; if(x<0)return -1; else return 1; } struct ShortestPath{ int rx[100009],ry[100009],s[100009],t[100009]; int cntedge; int head[maxn]; int to[100009],nex[100009]; double dist[100009]; void Addedge(int x,int y,double z){ nex[++cntedge]=head[x]; to[cntedge]=y; dist[cntedge]=z; head[x]=cntedge; } void readin(){ for(int i=1;i<=m;++i)scanf("%d%d%d%d",&rx[i],&ry[i],&t[i],&s[i]); } queue<int>q; int inq[maxn]; double d[maxn]; void Spfa(){ for(int i=1;i<=n;++i){ d[i]=oo;inq[i]=0; } inq[n]=1;d[n]=0;q.push(n); while(!q.empty()){ int x=q.front();q.pop();inq[x]=0; for(int i=head[x];i;i=nex[i]){ if(d[x]+dist[i]<d[to[i]]){ d[to[i]]=d[x]+dist[i]; if(!inq[to[i]]){ q.push(to[i]); inq[to[i]]=1; } } } } } int a[maxn],b[maxn],c[maxn]; void Div(int l,int r,double Lo,double Hi){ if(l>r)return; if(dcmp(Lo-Hi)==0){ for(int i=l;i<=r;++i)val[a[i]]=Lo; return; } double midans=(Lo+Hi)/2.0; memset(head,0,sizeof(head)); cntedge=0; for(int i=1;i<=m;++i)Addedge(rx[i],ry[i],t[i]-midans*s[i]); Spfa(); int t1=0,t2=0; for(int i=l;i<=r;++i){ if(d[a[i]]<=0){ b[++t1]=a[i]; }else{ c[++t2]=a[i]; } } for(int i=1;i<=t1;++i)a[l+i-1]=b[i]; for(int i=1;i<=t2;++i)a[l+t1+i-1]=c[i]; Div(l,l+t1-1,Lo,midans); Div(l+t1,r,midans,Hi); } void Getst(){ for(int i=1;i<=n1;++i)a[i]=i; for(int i=1;i<=n1;++i)val[i]=oo; Div(1,n1,0,1000.0); } }P; struct NetworkFlow{ struct Edge{ int from,to; double cap,flow; }; vector<int>G[maxn]; vector<Edge>edges; void Addedge(int x,int y,double z){ Edge e; e.from=x;e.to=y;e.cap=z;e.flow=0; edges.push_back(e); e.from=y;e.to=x;e.cap=0;e.flow=0; edges.push_back(e); int c=edges.size(); G[x].push_back(c-2); G[y].push_back(c-1); } int s,t; int d[maxn]; int vis[maxn]; queue<int>q; int Bfs(){ memset(vis,0,sizeof(vis)); vis[s]=1;d[s]=0;q.push(s); while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<G[x].size();++i){ Edge e=edges[G[x][i]]; if((dcmp(e.cap-e.flow)>0)&&(!vis[e.to])){ vis[e.to]=1; d[e.to]=d[x]+1; q.push(e.to); } } } return vis[t]; } double Dfs(int x,double a){ if((x==t)||(dcmp(a)==0))return a; double nowflow=0,f=0; for(int i=0;i<G[x].size();++i){ Edge e=edges[G[x][i]]; if(d[x]+1==d[e.to]){ f=Dfs(e.to,min(a,e.cap-e.flow)); if(dcmp(f)>0){ nowflow+=f; a-=f; edges[G[x][i]].flow+=f; edges[G[x][i]^1].flow-=f; if(dcmp(a)==0)break; } } } return nowflow; } double Maxflow(){ double flow=0; while(Bfs())flow+=Dfs(s,oo*1.0); return flow; } void Sol(){ s=n1+1;t=s+1; for(int i=1;i<=n1;++i){ if(i%2)Addedge(s,i,val[i]); else Addedge(i,t,val[i]); } while(m1--){ int x,y; scanf("%d%d",&x,&y); if((dcmp(val[x]-1000)==0)&&(dcmp(val[y]-1000)==0)){ printf("-1 ");return; } Addedge(x,y,oo*1.0); } printf("%.1f ",Maxflow()); } }F; int main(){ scanf("%d%d",&n,&m); P.readin(); scanf("%d%d",&m1,&n1); P.Getst(); F.Sol(); return 0; }