HDU 5988 2016青岛区域赛 (最小费用流)

题目链接

HDU 5988

分析

这题一看就是一个网络流的模板题,不过需要注意建边的费用!!
首先很容易想到,s与每个区域连一条边,费用为0,容量为 si ,区域与 t 连一条边 容量为 bi 费用为0。然后就是考虑区域与区域之间的连边了。

我们想象一下最终的分配方案,假设对于边 eij 来说,我们让 kij 个人通过,那么 eij 不被破坏的概率是 (1pij)kij ,整个网络被破坏的概率是

1(1pij)kij

因此我们需要最大化

(1pij)kij

然而最小费用流,不能干乘积最小这种事,它能干的是线性的目标函数,因此我们对目标函数取一个log

max kijln(1pij)

将费用取为 ln(1pij) 再加一条费用为0,流量为1的边就好了,套一下最小费用流模板

注意
由于花费是浮点数,在spfa里面注意加一个eps防止无限循环…..TLE到死

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
#define fi first
#define se second

using namespace std;

typedef long long LL;
typedef pair<int,int> Pair;
const   int oo=1e9;
const   int mm=4e4;
const   int mn=200;
const double eps = 1e-6;
int node,src,dest,edge;
int ver[mm],flow[mm],nex[mm];
double cost[mm];
int head[mn],p[mn],q[mn],vis[mn];
double dis[mn];
/**这些变量基本与最大流相同,增加了
 cost 表示边的费用,
 p 记录可行流上节点对应的反向边
 */
void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0; i1,vis[i]=0;
    edge=0;
}
void addedge(int u,int v,int f,double c)
{
    ver[edge]=v,flow[edge]=f,cost[edge]=c,nex[edge]=head[u],head[u]=edge++;
    ver[edge]=u,flow[edge]=0,cost[edge]=-c,nex[edge]=head[v],head[v]=edge++;
}
/**以上同最大流*/
/**spfa 求最短路,并用 p 记录最短路上的边*/
bool spfa()
{
    int i,u,v,l,r=0;
    double tmp;
    for(i=0; i0;
    p[src]=p[dest]=-1;
    for(l=0; l!=r; (++l>=mn)?l=0:l)
        for(i=head[u=q[l]],vis[u]=0; i>=0; i=nex[i])
            if(flow[i]&&dis[v=ver[i]]>(tmp=dis[u]+cost[i])+eps)
            {
                dis[v]=tmp;
                p[v]=i^1;
                if(vis[v]) continue;
                vis[q[r++]=v]=1;
                if(r>=mn)r=0;
            }
    return p[dest]>-1;
}
/**源点到汇点的一条最短路即可行流,不断的找这样的可行流*/
double SpfaFlow()
{
    int i,delta;
    double ret =0 ;
    while(spfa())
    {
        for(i=p[dest],delta=oo; i>=0; i=p[ver[i]])
            if(flow[i^1]1];
        for(i=p[dest]; i>=0; i=p[ver[i]])
            flow[i]+=delta,flow[i^1]-=delta;
        if(delta==0)break;
        ret+=delta*dis[dest];
    }
    return ret;
}
int main(int argc, char const *argv[]) {
    // ios_base::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);

    int T;
    scanf("%d",&T );
    while (T--) {
        int n,m;
        scanf("%d%d",&n,&m );

        int s = 0,t = n+1;
        prepare(n+2,s,t);
        for(int i=1 ; i<=n ; ++i){
            int si,bi;scanf("%d%d",&si,&bi );
            addedge(s,i,si,0);
            addedge(i,t,bi,0);
        }
        for(int i=1 ; i<=m ; ++i){
            int u,v,c;
            double p;
            scanf("%d%d%d%lf",&u,&v,&c,&p );
            addedge(u,v,1,0);
            addedge(u,v,c-1,-log(1-p));
        }
        // for(int i=1; i<=n ; ++i){
        //     std::cout << i << '\n';
        //     for(auto v : G[i]){
        //         std::cout << E[i]. << '\n';
        //     }
        // }

        //std::cout << ans << '\n';
        double ans =-SpfaFlow();
        //std::cout <<  ans << '\n';
        printf("%.2lf\n",1- exp(ans));
    }


  return 0;
}

你可能感兴趣的:(算法刷题)