• HDU6767 New Equipments(费用流+二分图性质)


    HDU6767 New Equipments

    题意:

    n个工人,m台设备。如果工人被分到第j台设备,则需要支付一个二次函数的费用。询问怎么设计方案使得找到K对工人和设备使得费用最小,输出K是1~n的答案

    题解:

    根据函数性质,确定工人在1~m里最小的n个点。

    0为超级源点

    1~n为工人

    n+1~n+x为工人们可能会用到的设备

    n+x+1为假汇点

    n+x+2为超级汇点

    源点向每个工人连容量为1,费用为0的边

    每个工人向各自前n小的点连容量为1,费用为cal(x)的边

    每个设备点向假汇点连容量为1,费用为0的边,表示设备只能用1次。

    假汇点向真汇点连一条容量为n,费用为0的边,表示选n次即可。

    考虑到二分图的性质,每增广一次后的答案就是当前K对应的答案。

    如果对每个K建新图,超时。

    如果用Map离散化设备编号,超时。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=55*55+55+10;
    int T,n,m;
    int M;
    const ll inf=1e18;
    int visit[maxn];
    int s,t;
    ll dis[maxn];
    int pre[maxn];
    int lst[maxn];
    ll flow[maxn];
    ll maxflow;
    ll mincost;
    
    struct node {
        int u,v;
        ll flow;
        ll dis;
        int nxt;
    }edge[maxn<<5];
    int tot,cnt;
    int head[maxn];
    void addedge (int u,int v,ll flow,ll dis) {
        edge[tot].u=u;
        edge[tot].v=v;
        edge[tot].flow=flow;
        edge[tot].dis=dis;
        edge[tot].nxt=head[u];
        head[u]=tot++;
        
        edge[tot].u=v;
        edge[tot].v=u;
        edge[tot].flow=0;
        edge[tot].dis=-dis;
        edge[tot].nxt=head[v];
        head[v]=tot++;
    }
    bool spfa (int s,int t) {
        for (int i=0;i<=t;i++) {
            dis[i]=inf;flow[i]=inf;visit[i]=0;
        }
        queue<int> q;q.push(s);
        visit[s]=1;
        dis[s]=0;
        pre[t]=-1;
        while (q.size()) {
            int u=q.front();q.pop();
            visit[u]=0;
            for (int i=head[u];i!=-1;i=edge[i].nxt) {
                if (edge[i].flow>0&&dis[edge[i].v]>dis[u]+edge[i].dis) {
                    dis[edge[i].v]=dis[u]+edge[i].dis;
                    pre[edge[i].v]=u;
                    lst[edge[i].v]=i;
                    flow[edge[i].v]=min(flow[u],edge[i].flow);
                    if (!visit[edge[i].v]) {
                        visit[edge[i].v]=1;
                        q.push(edge[i].v);
                    }
                }
            } 
        }
        return pre[t]!=-1;
    }
    void mcmf () {
        maxflow=0;
        mincost=0;
        int num=0;
        while (spfa(s,t)) {
            int u=t;
            maxflow+=flow[t];
            mincost+=flow[t]*dis[t];
            while (u!=s) {
                edge[lst[u]].flow-=flow[t];
                edge[lst[u]^1].flow+=flow[t];
                u=pre[u];
            }
            printf("%lld",mincost);
            num++;
            if (num<n)
                printf(" ");
            else
                printf("
    ");
        }
    }
    
    ll a[maxn];
    ll b[maxn];
    ll c[maxn];
    ll cal (ll A,ll B,ll C,ll X) {
        return A*X*X+B*X+C;
    }
    vector<int> g[maxn];//每个点对应的前n小的设备
    double A,B,C;
    bool cmp (int x,int y) {
        return cal(A,B,C,x)<cal(A,B,C,y);
    }
    void get (int x) {
        //预处理出点x对应的前n小的点 
        int p=-1.0*b[x]/(a[x]*2);
        if (p<=1) p=1;
        if (p>=m) p=m;
        for (int i=p;i<=min(m,p+n);i++) g[x].push_back(i);
        for (int i=p-1;i>=max(1,p-n);i--) g[x].push_back(i);
        A=a[x];B=b[x];C=c[x];
        sort(g[x].begin(),g[x].end(),cmp);
    } 
    int lsh[maxn];
    int main () {
        scanf("%d",&T);
        while (T--) {
            scanf("%d%d",&n,&m);
            for (int i=1;i<=n;i++) scanf("%lld%lld%lld",&a[i],&b[i],&c[i]),g[i].clear();
            for (int i=1;i<=n;i++) get(i);
            tot=0;
            for (int i=1;i<=n;i++) for (int j=0;j<min(n,(int)g[i].size());j++) lsh[++tot]=g[i][j];
            sort(lsh+1,lsh+tot+1);
            M=unique(lsh+1,lsh+tot+1)-lsh-1;
            for (int i=0;i<maxn;i++) head[i]=-1;tot=0;
            s=0;
            for (int i=1;i<=n;i++) {
                addedge(s,i,1,0);
                for (int j=0;j<min((int)g[i].size(),n);j++) {
                    int p=upper_bound(lsh+1,lsh+M+1,g[i][j])-lsh-1;
                    addedge(i,n+p,1,cal(a[i],b[i],c[i],g[i][j]));
                }
            }
            t=n+M+2;
            for (int i=1;i<=M;i++) {
                addedge(n+i,n+M+1,1,0);
            }
            addedge(n+M+1,t,n,0);
            mcmf();
        }
    }
  • 相关阅读:
    Vue中computed和watch的区别
    JS基础语法
    JDBC
    表设计
    查询语句
    反射
    网络端
    多线程
    HashMap
    IO
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13714458.html
Copyright © 2020-2023  润新知