P2494 [SDOI2011]保密 最小割

  洛谷

题意:

给定n个点有m1个军事基地要探索,每个军事基地有两个出入口u,v (u,v 属于1-n1点)只要到达一个出入口(1-n1) 就可以探索与其相连的所有的出入口, 问最少的代价探索所有的出入口

m 条有向边 ,形成DAG, 每条边有两个属性s,t,路径代价为 经过所有边的 s属性和/t属性和。起始点在n点。

题解:

  •  主要可以转化为两个问题

  • 求n到每个出入口的时间和与安全系数和比值最小的路径
  • 求出探索所有空腔的最小代价
  • 前者是一个分数规划问题,二分 加最短路验证即可
  • 后者是一个最小割问题
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define eps 1e-8
const int N=1e5+10;
const int M=1e5+10;
struct Edge {
    int to, next;double w;
} edge[M<<1];
int head[N],cur[N],pos=1,level[N];
void add(int a, int b, double c) {
    edge[++pos] = (Edge){b, head[a], c};head[a] = pos;
    edge[++pos] = (Edge){a, head[b], 0};head[b] = pos;
}
bool bfs(int s, int t) {
    memset(level, 0, sizeof level);
    queue<int> q;
    level[s] = 1;
    q.push(s);
    while (!q.empty()) {
        int pos = q.front();q.pop();
        for (int i = head[pos]; i; i = edge[i].next) {
            int v = edge[i].to;
            if ( fabs(edge[i].w-0)<=eps || level[v]) continue;
            level[v] = level[pos] + 1;
            q.push(v);
        }
    }
    return level[t];
}
double dfs(int s, int t, double flow) {
    if(s==t||fabs(flow-0)<=eps)return flow;
    double f,ret = 0;
    for (int i = cur[s],v; i; i = edge[i].next) {
         v = edge[i].to;
        if (level[v] == level[s] + 1 && (f=dfs(v,t,min(flow,edge[i].w)))>=eps) {
            edge[i].w -= f;
            edge[i ^ 1].w += f;
            flow -= f;
            ret += f;
            if(!flow)break;
        }
    }
    return ret;
}
double dinic(int s, int t) {
    double ret = 0;
    while (bfs(s, t)) memcpy(cur,head,sizeof cur),ret += dfs(s, t, 1e50);
    return ret;
}

struct Edge2{int to,nex;double t,s;}edge2[N<<1];
int head2[N],pos2;
void addtp(int a,int b,double c,double d) {
    edge2[++pos2]=(Edge2){b,head2[a],c,d};head2[a]=pos2;
}
int n,m,s,t;
double val[N];

int vis[N];double dis[N];
bool check(int s,int t,double x) {
    for(int i=1;i<=n;i++)dis[i]=1e50,vis[i]=0;
    vis[s]=1;dis[s]=0;
    queue<int>q;while(!q.empty())q.pop();
    q.push(s);
    while(!q.empty()) {
        int u=q.front();q.pop();vis[u]=0;
        for(int i=head2[u];i;i=edge2[i].nex) {
            int v=edge2[i].to;
            if(dis[v]>dis[u]+edge2[i].t-edge2[i].s*x) {
                dis[v]=dis[u]+edge2[i].t-edge2[i].s*x;
                if(v==t&&dis[v]<eps)return 1;
                if(!vis[v])vis[v]=1,q.push(v);
            }
        }
    }
    return dis[t]<-eps;
}

int main() {
    cin>>n>>m;int a,b;double c,d;
    while(m--) {
        scanf("%d%d%lf%lf",&a,&b,&c,&d);
        addtp(a,b,c,d);
    }
    int n1,m1;
    cin>>m1>>n1;

    for(int i=1;i<=n1;i++) {
        double L=0,R=100,ans=0;
        while(L<R-1e-4) {
            double mid=(L+R)*0.5;
            if(check(n,i,mid))ans=mid,R=mid;
            else L=mid;
        }
        if(ans==0)val[i]=1e50;
        else val[i]=ans;
    }
    s=n1+1,t=s+1;int u,v;
    for(int i=1;i<=m1;i++) {
        scanf("%d%d",&u,&v);
        if(v&1)swap(u,v);
        if(val[u]==1e50&&val[v]==1e50)return printf("-1"),0;
        add(u,v,1e50);
    }
    for(int i=1;i<=n1;i++)
        if(i&1) add(s,i,val[i]);
        else add(i,t,val[i]);
    printf("%.1f",dinic(s,t));
}
View Code