zoukankan      html  css  js  c++  java
  • 【BZOJ1070】修车(SCOI2007)-费用流+拆点

    测试地址:修车
    做法:本题需要用到费用流+拆点。
    我们很容易想到将技术人员和车匹配起来,但这样有一个问题:当一个技术人员修多辆车的时候,产生的费用不能简单地用相加来刻画。因此我们需要运用一个方法:拆点。
    将每个技术人员拆成n个点,然后将这些点和车匹配,第i个点和第j辆车匹配表示这个技术人员修的倒数第i辆车为j,就会产生一些费用。我们知道,如果这个技术人员修这辆车的时间为k,且是他修的倒数第i辆车,那么会产生ik的费用,把这个作为中间连边的费用即可。这样这个图的最小边权最大匹配就是答案,这也就是最小费用最大流的经典应用了。
    为什么这个方法是对的呢?我们显然可以证明,如果一个技术员的第i个点在最后是被匹配上的,那么这个技术员的第1,2,...,i1个点肯定同时也已经被匹配上了,否则就会产生更小的费用,和最小费用最大流的假设矛盾。这样建模之后,就可以刻画一个技术人员修多辆车产生的费用了,于是我们就完成了这一题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int n,m,S,T,g[70][15];
    int first[1010]={0},tot=1,dis[1010],laste[1010],last[1010];
    bool vis[1010];
    queue<int> Q;
    struct edge
    {
        int v,next,f,c;
    }e[300010];
    
    void insert(int a,int b,int f,int c)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,e[tot].c=c,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,e[tot].c=-c,first[b]=tot;
    }
    
    void init()
    {
        scanf("%d%d",&m,&n);
        S=n*m+n+1,T=n*m+n+2;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&g[i][j]);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
            {
                insert(S,(i-1)*n+j,1,0);
                for(int k=1;k<=n;k++)
                    insert((i-1)*n+j,n*m+k,1,g[k][i]*j);
            }
        for(int i=1;i<=n;i++)
            insert(n*m+i,T,1,0);
    }
    
    bool spfa()
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=T;i++)
            dis[i]=inf;
        Q.push(S);
        dis[S]=0;
        vis[S]=1;
        while(!Q.empty())
        {
            int v=Q.front();Q.pop();
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&dis[e[i].v]>dis[v]+e[i].c)
                {
                    dis[e[i].v]=dis[v]+e[i].c;
                    laste[e[i].v]=i;
                    last[e[i].v]=v;
                    if (!vis[e[i].v]) vis[e[i].v]=1,Q.push(e[i].v);
                }
            vis[v]=0;
        }
        return dis[T]!=inf;
    }
    
    void mincost()
    {
        int minc=0;
        while(spfa())
        {
            int x=T,maxf=inf;
            while(x!=S)
            {
                maxf=min(maxf,e[laste[x]].f);
                x=last[x];
            }
            x=T;
            while(x!=S)
            {
                e[laste[x]].f-=maxf;
                e[laste[x]^1].f+=maxf;
                x=last[x];
            }
            minc+=maxf*dis[T];
        }
        printf("%.2lf",(double)minc/(double)n);
    }
    
    int main()
    {
        init();
        mincost();
    
        return 0;
    }
  • 相关阅读:
    微信小程序 单选按钮 最佳
    微信小程序 单选按钮的实现
    微信小程序 单选框实现
    Java Code To Create Pyramid and Pattern
    Java language
    npm Err! Unexpected end of JSON input while parsing near
    Node.js Express FrameWork Tutorial
    Higher-Order Function Examples
    Create First HTTP Web Server in Node.js: Complete Tutorial
    Node.js NPM Tutorial: Create, Publish, Extend & Manage
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793429.html
Copyright © 2011-2022 走看看