hdu 4780 Candy Factory(费用流)

题意:给出m个机器,现在要生产n个糖果,每个糖果可以在任意一个机器上生产,每个糖果的生产时间是一个区间[s,t],必须在[s,t)时间内开始生产,否则就无法生产了,生产的费用为(p-s)*k,p是开始生产的时间。对于一个机器j来说,从最开始没生产的状态转化为生产第i个糖果的状态需要花费C[i][j]的时间并花费D[i][j],对于一个在生产第i个糖果的机器来说,将其转化为生产第j个糖果需要花费E[i][j]的时间并花费F[i][j],现在要生产这n个糖果并让所有花费最小。

思路:一看就是个网络流的问题,不过建图还是有些麻烦的,首先将n个糖果拆成两个点,如果左边第i个糖果生产完,可以生产右边的j,那么连边,流量为1,费用为转换的费用+生产费用,S向左边的点连边,流量为1,费用为0,右边的点向T连边,流量为1,费用为0。添加点u,从S向u连边,流量为m,费用为0,再从u向m个点连边,流量为1,费用为0,接下来m个点代表最开始这个机器生产哪个糖果,如果可以最开始生产某个糖果,向右边的对应点连边,流量为1,费用为转换费用+生产费用。这样就能保证最后的费用流就是答案。


代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-6
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=300+10;
const int maxm=100000+10;
struct Edge
{
    int to,cap,cost,next;
    Edge(int to=0,int cap=0,int cost=0,int next=0):to(to),cap(cap),cost(cost),next(next){}
}edges[maxm<<1];
int head[maxn],d[maxn],a[maxn],p[maxn],nEdge,S,T;
bool inq[maxn];
int st[maxn],tt[maxn],C[maxn][maxn],D[maxn][maxn],E[maxn][maxn],F[maxn][maxn];
void AddEdges(int from,int to,int cap,int cost)
{
    edges[++nEdge]=Edge(to,cap,cost,head[from]);
    head[from]=nEdge;
    edges[++nEdge]=Edge(from,0,-cost,head[to]);
    head[to]=nEdge;
}
int spfa(int &flow,int &cost)
{
    memset(inq,0,sizeof(inq));
    memset(d,0x3f,sizeof(d));
    queue<int>q;
    q.push(S);
    d[S]=0;a[0]=inf;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        inq[u]=false;
        for(int k=head[u];k!=-1;k=edges[k].next)
        {
            Edge &e=edges[k];
            if(d[e.to]>d[u]+e.cost&&e.cap)
            {
                d[e.to]=d[u]+e.cost;
                a[e.to]=min(a[u],e.cap);
                p[e.to]=k;
                if(!inq[e.to]) {inq[e.to]=true;q.push(e.to);}
            }
        }
    }
    if(d[T]==inf) return false;
    flow+=a[T];
    cost+=a[T]*d[T];
    int u=T;
    while(u!=S)
    {
        edges[p[u]].cap-=a[T];
        edges[p[u]^1].cap+=a[T];
        u=edges[p[u]^1].to;
    }
    return true;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m,K;
    while(~scanf("%d%d%d",&n,&m,&K))
    {
        if(n==0&&m==0&&K==0) break;
        memset(head,0xff,sizeof(head));
        nEdge=-1;
        for(int i=1;i<=n;++i)
            scanf("%d%d",&st[i],&tt[i]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                scanf("%d",&C[i][j]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                scanf("%d",&D[i][j]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&E[i][j]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&F[i][j]);
        S=0,T=n*2+m+2;
        for(int i=1;i<=n;++i)
        {
            AddEdges(S,i,1,0);
            AddEdges(i+n,T,1,0);
            for(int j=1;j<=n;++j)
            {
                if(i!=j&&tt[i]+E[i][j]<tt[j])
                {
                    int c=max(tt[i]+E[i][j],st[j])-st[j];
                    c*=K;
                    AddEdges(i,n+j,1,c+F[i][j]);
                }
            }
        }
        AddEdges(S,n*2+m+1,m,0);
        for(int i=1;i<=m;++i)
        {
            AddEdges(n*2+m+1,n*2+i,1,0);
            for(int j=1;j<=n;++j)
            {
                if(C[j][i]<tt[j])
                {
                    int c=max(C[j][i],st[j])-st[j];
                    c*=K;
                    AddEdges(n*2+i,j+n,1,c+D[j][i]);
                }
            }
        }
        int flow=0,cost=0;
        while(spfa(flow,cost));
        if(flow!=n) printf("-1\n");
        else printf("%d\n",cost);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值