• 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
  • 相关阅读:
    【转】Android-Input input&按键布局文件
    【转】Android-Input 触摸设备
    【转】IE沙箱拖拽安全策略解析
    FireFox 插件xpi文件签名2
    如何给Firefox附加组件签名
    【转】用opencv使摄像头在30fps下捕获1080p的数据
    Displaylink安卓驱动
    无主之地2 不费子弹手枪
    jsoncpp
    [APIO2010] 算法竞赛竞赛经典 巡逻
  • 原文地址:https://www.cnblogs.com/bxd123/p/11822064.html
Copyright © 2020-2023  润新知