首页 > 代码库 > [SDOI2011]工作安排
[SDOI2011]工作安排
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
HINT
这道题题意比较明朗,毕竟是山东省选题,不过这么裸的费用流我也是无语了,建立一个S与T。
然后以零件个数让每个零件与T建立一条花费为0,流量为工件数的边,然后那个人可以做哪几个工件就是,让人的编号与工件编号连一条花费为0,流量为无限的边,
然后让起点与每个人以分段函数建边,以愤怒值为花费,做的数量为流量,然后跑一次最小费用最大流就好了,用朴素的spfa的算法,就可以了。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 #include<queue> 7 using namespace std; 8 9 const int INF=1e9+7,NN=257*2+7,MM=200007; 10 11 int n,m,S,T; 12 int cnt,head[NN]={0},next[MM]={0},rea[MM]={0},val[MM]={0},cost[MM]={0}; 13 int dis[NN]={0},flag[NN]={0},num[NN]={0},a[NN][NN]={0},E[NN][7]={0},W[NN][7]={0}; 14 struct Node 15 { 16 int e,fa; 17 void init(){e=fa=-1;} 18 }pre[NN]; 19 20 void add(int u,int v,int fee,int fare) 21 { 22 cnt++; 23 next[cnt]=head[u]; 24 head[u]=cnt; 25 rea[cnt]=v; 26 val[cnt]=fee; 27 cost[cnt]=fare; 28 } 29 void build() 30 { 31 for (int i=1;i<=m;i++) 32 for (int j=1;j<=n;j++) 33 if (a[i][j]) add(i,j+m,INF,0),add(j+m,i,0,0); 34 for (int i=1;i<=m;i++) 35 for (int j=1;j<=num[i]+1;j++) 36 add(S,i,E[i][j]-E[i][j-1],W[i][j]),add(i,S,0,-W[i][j]); 37 } 38 bool Spfa() 39 { 40 for (int i=1;i<=n+m+2;i++) 41 { 42 flag[i]=0; 43 dis[i]=INF; 44 pre[i].init(); 45 } 46 dis[S]=0,flag[S]=1; 47 queue<int>q; 48 while(!q.empty()) q.pop(); 49 q.push(S); 50 while(!q.empty()) 51 { 52 int u=q.front(); 53 q.pop(); 54 for (int i=head[u];i!=-1;i=next[i]) 55 { 56 int v=rea[i],fee=cost[i]; 57 if ((dis[v]>dis[u]+fee)&&val[i]>0) 58 { 59 dis[v]=dis[u]+fee; 60 pre[v].e=i; 61 pre[v].fa=u; 62 if (flag[v]==0) 63 { 64 flag[v]=1; 65 q.push(v); 66 } 67 } 68 } 69 flag[u]=0; 70 } 71 if (dis[T]==INF) return 0; 72 else return 1; 73 } 74 long long MFMC() 75 { 76 long long res=0,flow=0; 77 while (Spfa()) 78 { 79 int x=INF; 80 for (int i=T;pre[i].fa!=-1;i=pre[i].fa) 81 { 82 int e=pre[i].e; 83 x=min(x,val[e]); 84 } 85 flow+=x,res=(long long)(res+dis[T]*x); 86 for (int i=T;pre[i].fa!=-1;i=pre[i].fa) 87 { 88 int e=pre[i].e; 89 val[e]-=x,val[e^1]+=x; 90 } 91 } 92 return res; 93 } 94 int main() 95 { 96 cnt=1; 97 memset(head,-1,sizeof(head)); 98 scanf("%d%d",&m,&n); 99 S=m+n+1,T=n+m+2; 100 int x; 101 for (int i=1;i<=n;i++) 102 { 103 scanf("%d",&x); 104 add(i+m,T,x,0),add(T,i+m,0,0); 105 } 106 for (int i=1;i<=m;i++) 107 for (int j=1;j<=n;j++) 108 scanf("%d",&a[i][j]); 109 for (int t=1;t<=m;t++) 110 { 111 scanf("%d",&num[t]); 112 for (int i=1;i<=num[t];i++) 113 scanf("%d",&E[t][i]); 114 E[t][num[t]+1]=INF; 115 for (int i=1;i<=num[t]+1;i++) 116 scanf("%d",&W[t][i]); 117 } 118 build(); 119 printf("%lld\n",MFMC()); 120 }
[SDOI2011]工作安排