[SCOI2007][bzoj1070] 修车 [费用流]
2018-04-07 14:21
459 查看
题面
传送门思路
我们考虑某个工人修车的从前到后序列如下:${W_1,W_2,W_3,...,W_n}$
那么,对于这n辆车的车主而言,他们等候的总时间为:
$\sum_{i=1}^{n}W_i\ast\left(n-i+1\right)=nW_1+\left(n-1\right)W_2+...+2W_{n-1}+W_n$
这一步很重要,因为经过这一步推导,我们发现:对于“把第i辆车让第j个人在“需要消耗k次时间”的那个个位置修”这一个决策,可以等同为进行一个费用为$T\left(i,j\right)\ast k$的决策
因此我们可以得到一个决策集合:决策$\left(i,j,k\right)=T\left(i,j\right)\ast k$表示“把第i辆车让第j个人在“需要消耗k次时间”的那个个位置修”
那实际上我们就是对于每个i选取一个这样的决策,同时这个决策的$\left(j,k\right)$不能相同
那就好办了,我们建立一个二分图,左边是n辆车,右边是n*m个上述状态的二元组$\left(j,k\right)$(可以证明$k\leq n$)
源点向车连边,而决策二元组向汇点连边,流量1费用0
中间的边(注意这是一个完全二分图)就是流量1费用$T\left(i,j\right)\ast k$的
跑最小费用最大流即可
Code:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define inf 1e9 #define id(i,j) (i-1)*n+j using namespace std; inline int read(){ int re=0,flag=1;char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') flag=-1; ch=getchar(); } while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); return re*flag; } int n,m,cnt=-1,ans,first[1010],dis[1010],vis[1010]; struct edge{ int to,next,w,cap; }a[100010]; inline void add(int u,int v,int w,int cap){ a[++cnt]=(edge){v,first[u],w,cap};first[u]=cnt; a[++cnt]=(edge){u,first[v],-w,0};first[v]=cnt; } bool spfa(int s,int t){ int q[5010],head=0,tail=1,u,v,w,i; memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis)); q[0]=t;vis[t]=1;dis[t]=0; while(head<tail){ u=q[head++];vis[u]=0; for(i=first[u];~i;i=a[i].next){ v=a[i].to;w=a[i].w; if(a[i^1].cap&&((dis[v]==-1)||(dis[v]>dis[u]-w))){ dis[v]=dis[u]-w; if(!vis[v]) vis[v]=1,q[tail++]=v; } } } return ~dis[s]; } int dfs(int u,int t,int limit){ if(u==t||!limit){vis[u]=1;return limit;} int i,v,f,flow=0,w;vis[u]=1; for(i=first[u];~i;i=a[i].next){ v=a[i].to;w=a[i].w; if(!vis[v]&&a[i].cap&&(dis[v]==dis[u]-w)){ if(!(f=dfs(v,t,min(limit,a[i].cap)))) continue; a[i].cap-=f;a[i^1].cap+=f; ans+=f*w;flow+=f;limit-=f; if(!limit) return flow; } } return flow; } int zkw(int s,int t){//zkw费用流 int re=0; while(spfa(s,t)){ vis[t]=1; while(vis[t]){ memset(vis,0,sizeof(vis)); re+=dfs(s,t,inf); } } return re; } int main(){ memset(first,-1,sizeof(first));int i,j,k,t1; m=read();n=read(); for(i=1;i<=n;i++) add(0,i,0,1); for(i=1;i<=m;i++) for(j=1;j<=n;j++) add(n+id(i,j),n+n*m+1,0,1); for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ t1=read(); for(k=1;k<=n;k++){ add(i,n+id(j,k),t1*k,1); } } } zkw(0,n+n*m+1); printf("%.2lf",((double)ans)/((double)n));//注意输出保留两位小数 }
相关文章推荐
- [BZOJ 1070] [SCOI2007] 修车 【费用流】
- bzoj 1070: [SCOI2007]修车 -- 费用流
- bzoj 1070: [SCOI2007]修车 费用流
- [BZOJ 1070][SCOI2007]修车:费用流
- [BZOJ1070][SCOI2007]修车(费用流)
- BZOJ 1070: [SCOI2007]修车(费用流)
- [BZOJ1070][SCOI2007]修车(费用流)
- [bzoj1070][SCOI2007]修车_费用流
- 【BZOJ 1070】[SCOI2007]修车 费用流
- [BZOJ1070]SCOI2007修车|费用流
- BZOJ 1070: [SCOI2007]修车 费用流
- BZOJ_1070_[SCOI2007]修车_费用流
- bzoj 1070: [SCOI2007]修车(费用流)[省选计划系列]
- BZOJ 1070 [SCOI2007]修车【费用流
- 【费用流丨二分图最佳匹配】 [SCOI 2007] bzoj1070 修车
- BZOJ 1070: [SCOI2007]修车 费用流
- [bzoj1070][SCOI2007]修车【费用流】
- bzoj1070 [SCOI2007]修车 费用流
- [BZOJ1070] [SCOI2007]修车 && 二分图最佳完美匹配 或 费用流
- [bzoj1070][SCOI2007]修车 费用流