Bzoj 2245: [SDOI2011]工作安排(费用流)

    xiaoxiao2021-03-26  4

    2245: [SDOI2011]工作安排 Time Limit: 20 Sec Memory Limit: 512 MB Description 你的公司接到了一批订单。订单要求你的公司提供n类产品,产品被编号为1~n,其中第i类产品共需要Ci件。公司共有m名员工,员工被编号为1~m员工能够制造的产品种类有所区别。一件产品必须完整地由一名员工制造,不可以由某名员工制造一部分配件后,再转交给另外一名员工继续进行制造。 我们用一个由0和1组成的m*n的矩阵A来描述每名员工能够制造哪些产品。矩阵的行和列分别被编号为1~m和1~n,Ai,j为1表示员工i能够制造产品j,为0表示员工i不能制造产品j。 如果公司分配了过多工作给一名员工,这名员工会变得不高兴。我们用愤怒值来描述某名员工的心情状态。愤怒值越高,表示这名员工心情越不爽,愤怒值越低,表示这名员工心情越愉快。员工的愤怒值与他被安排制造的产品数量存在某函数关系,鉴于员工们的承受能力不同,不同员工之间的函数关系也是有所区别的。 对于员工i,他的愤怒值与产品数量之间的函数是一个Si+1段的分段函数。当他制造第1~Ti,1件产品时,每件产品会使他的愤怒值增加Wi,1,当他制造第Ti,1+1~Ti,2件产品时,每件产品会使他的愤怒值增加Wi,2……为描述方便,设Ti,0=0,Ti,si+1=+∞,那么当他制造第Ti,j-1+1~Ti,j件产品时,每件产品会使他的愤怒值增加Wi,j, 1≤j≤Si+1。 你的任务是制定出一个产品的分配方案,使得订单条件被满足,并且所有员工的愤怒值之和最小。由于我们并不想使用Special Judge,也为了使选手有更多的时间研究其他两道题目,你只需要输出最小的愤怒值之和就可以了。 Input 第一行包含两个正整数m和n,分别表示员工数量和产品的种类数; 第二行包含n 个正整数,第i个正整数为Ci; 以下m行每行n 个整数描述矩阵A; 下面m个部分,第i部分描述员工i的愤怒值与产品数量的函数关系。每一部分由三行组成:第一行为一个非负整数Si,第二行包含Si个正整数,其中第j个正整数为Ti,j,如果Si=0那么输入将不会留空行(即这一部分只由两行组成)。第三行包含Si+1个正整数,其中第j个正整数为Wi,j。 Output 仅输出一个整数,表示最小的愤怒值之和。 Sample Input 2 3 2 2 2 1 1 0 0 0 1 1 2 1 10 1 2 1 6 Sample Output 24 HINT Sourc 第一轮day2

    /* 费用流. 对于每个员工的不同时刻拆点. 由源点连边,流量为Tj-Tj-1,费用为w[j]. 由员工向可做工作连边,流量为INF,费用为0. 最后由工作向汇点连边,流量为c[j],费用为0. 我们要保证连边费用的正确性和满流. 因为我们相当于是贪心的跑费用, 任意员工对于任意时刻的费用是单调不升的, 所以我们能够保证它正确. 我们注意到dinic的复杂度是n^2m的. 这样直接做会超时, 我们可以不用拆点, 直接对于员工建S+1条边, 这样做是等价的。 还有这题要用longlong... */ #include<iostream> #include<cstdio> #include<queue> #define MAXN 260 #define INF 1e9 #define LL long long using namespace std; int n,m,cut=1,S,T,c[MAXN],head[MAXN*2],pre[MAXN*2],a[MAXN][MAXN],p[MAXN],t[MAXN][MAXN],w[MAXN][MAXN],s[MAXN],b[MAXN*2]; struct edge{int u,v,next,f,c;}e[MAXN*MAXN*30]; LL dis[MAXN*2],ans; queue<int>q; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return x*f; } inline void add(int u,int v,int c,int f) { e[++cut].u=u;e[cut].next=head[u];e[cut].v=v,e[cut].f=f,e[cut].c=c;head[u]=cut; e[++cut].u=v;e[cut].next=head[v];e[cut].v=u;e[cut].f=-f;e[cut].c=0;head[v]=cut; } inline bool bfs(int tag) { for(int i=S;i<=T;i++) dis[i]=1e18;dis[S]=0;q.push(S); while(!q.empty()) { int u=q.front();q.pop();b[u]=0; for(int i=head[u];i;i=e[i].next) { if(dis[e[i].v]>dis[u]+e[i].f&&e[i].c) { dis[e[i].v]=dis[u]+e[i].f;pre[e[i].v]=i; if(b[e[i].v]!=tag) b[e[i].v]=tag,q.push(e[i].v); } } } return dis[T]!=1e18; } void mincost() { int tag=1,tmp,x; while(bfs(tag)) { tmp=pre[T],x=INF; while(tmp) x=min(x,e[tmp].c),tmp=pre[e[tmp].u]; tmp=pre[T]; while(tmp) { e[tmp].c-=x; e[tmp^1].c+=x; tmp=pre[e[tmp].u]; } ans+=dis[T]*x; tag++; } return ; } void slove() { S=0,T=n+m+1; for(int i=1;i<=m;i++) { for(int k=1;k<=s[i]+1;k++) add(S,i,t[i][k]-t[i][k-1],w[i][k]); } for(int i=1;i<=n;i++) add(i+m,T,c[i],0); mincost(); return ; } int main() { freopen("job.in","r",stdin); freopen("job.out","w",stdout); m=read();n=read(); for(int i=1;i<=n;i++) c[i]=read(); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { a[i][j]=read(); if(a[i][j]) add(i,j+m,INF,0); } for(int i=1;i<=m;i++) { s[i]=read(); for(int j=1;j<=s[i];j++) t[i][j]=read(); t[i][s[i]+1]=INF; for(int j=1;j<=s[i]+1;j++) w[i][j]=read(); } slove(); cout<<ans<<endl; return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-600401.html

    最新回复(0)