BZOJ2285 : [Sdoi2011]保密

首先通过分数规划,二分答案$mid$,将每条边边权重置为$t-mid imes s$,用DP求出终点到该点的最短路,若非正则可以更小。

如此可以计算出每个出入口的最小危险值,然后把奇点放在$S$,偶点放在$T$,代价为危险值,对于每个空腔,在相应点之间连无穷边,求最小割即可。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=705,M=100010;
const double inf=1e9,eps=3e-4;
int n,m,n1,m1,i,x,y,d[N],g[N],v[M],wt[M],ws[M],nxt[M],ed,h,t,q[N],vis[N];double f[N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y){d[y]++;v[++ed]=y;read(wt[ed]);read(ws[ed]);nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
  if(vis[x])return;
  vis[x]=1;
  for(int i=g[x];i;i=nxt[i])dfs(v[i]);
}
inline bool check(int T,double p){
  int i,x,j;
  for(i=1;i<n;i++)f[i]=inf;
  for(i=1;i<=n;i++){
    x=q[i];
    if(x==T)return f[x]<eps;
    for(j=g[x];j;j=nxt[j])f[v[j]]=min(f[v[j]],f[x]+wt[j]-p*ws[j]);
  }
}
inline double cal(int x){
  if(!vis[x])return inf;
  double l=0.1,r=10,mid;
  while(l+eps<r)if(check(x,mid=(l+r)/2))r=mid;else l=mid;
  return(l+r)/2;
}
namespace Flow{
struct E{int t;double f;E*nxt,*pair;}*g[N],*d[N],pool[90000],*cur=pool;
int S,T,h[N],gap[N];double ans;
inline void add(int s,int t,double f){
  E*p=cur++;p->t=t;p->f=f;p->nxt=g[s];g[s]=p;
  p=cur++;p->t=s;p->f=0;p->nxt=g[t];g[t]=p;
  g[s]->pair=g[t];g[t]->pair=g[s];
}
double sap(int v,double flow){
  if(v==T)return flow;
  double rec=0;
  for(E*p=d[v];p;p=p->nxt)if(h[v]==h[p->t]+1&&p->f>eps){
    double ret=sap(p->t,min(flow-rec,p->f));
    p->f-=ret;p->pair->f+=ret;d[v]=p;
    rec+=ret;
    if(rec+eps>flow)return flow;
  }
  if(!(--gap[h[v]]))h[S]=T;
  gap[++h[v]]++;d[v]=g[v];
  return rec;
}
void solve(){
  for(gap[0]=T,i=1;i<=T;i++)d[i]=g[i];
  while(h[S]<T)ans+=sap(S,inf);
  if(ans>1e8)puts("-1");else printf("%.1f",ans);
}
}
int main(){
  read(n),read(m);
  for(i=1;i<=m;i++)read(x),read(y),add(x,y);
  dfs(n);
  for(h=i=1;i<=n;i++)if(!d[i])q[++t]=i;
  while(h<=t)for(i=g[x=q[h++]];i;i=nxt[i])if(!(--d[v[i]]))q[++t]=v[i];
  read(m1),read(n1);
  Flow::S=n1+1;
  Flow::T=n1+2;
  for(i=1;i<=n1;i++)if(i&1)Flow::add(n1+1,i,cal(i));else Flow::add(i,n1+2,cal(i));
  while(m1--)read(x),read(y),Flow::add(x,y,inf);
  Flow::solve();
  return 0;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/5792052.html