bzoj1070: [SCOI2007]修车
Posted invoid
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1070: [SCOI2007]修车相关的知识,希望对你有一定的参考价值。
最小费用最大流。
这道题的特点在于每个修车的人所需要等待的时间要加上之前这个技术人员维修车的时间。
直观地我们可以每个技术人员建造n个点,费用分别为k*t(k=1,2,3…)(t为维修时间)。
但是这样很可能会超时,我们又发现,因为总共只有n个人来修车,我们每次用过每个修车人员后,再临时增加点,就可以避免浪费。
决策时,就变成了这个技术人员倒数第几个修这个车。
语言比较混乱,但这道题是好题。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 10000 + 10; const int maxm = 1000000 + 10; const int inf = 0x3f3f3f3f; int g[maxn],v[maxm],next[maxm],f[maxm],c[maxm],eid; int id[10][maxn],cnt[10],vid; int dist[maxn],pre[maxn]; int q[maxm],l,r; bool inque[maxn]; int t[110][20]; int m,n,res,S,T; void addedge(int a,int b,int C) { v[eid]=b; f[eid]=1; c[eid]=C; next[eid]=g[a]; g[a]=eid++; v[eid]=a; f[eid]=0; c[eid]=-C; next[eid]=g[b]; g[b]=eid++; } void build() { scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&t[i][j]); memset(g,-1,sizeof(g)); S=0; T=maxn-1; vid=n; for(int i=1;i<=n;i++) addedge(S,i,0); for(int p=1;p<=m;p++) { id[p][++cnt[p]]=++vid; addedge(vid,T,0); for(int i=1;i<=n;i++) addedge(i,vid,t[i][p]); } } void augment() { for(int i=T;i!=S;i=v[pre[i]^1]) { f[pre[i]]--; f[pre[i]^1]++; } res+=dist[T]; } int SPFA() { memset(dist,0x3f,sizeof(dist)); memset(pre,-1,sizeof(pre)); l=r=0; dist[S]=0; inque[q[r++]=S]=1; int u; while(l<r) { inque[u=q[l++]]=0; for(int i=g[u];~i;i=next[i]) if(f[i] && dist[v[i]]>dist[u]+c[i]) { dist[v[i]]=c[i]+dist[u]; pre[v[i]]=i; if(!inque[v[i]]) inque[q[r++]=v[i]]=1; } } augment(); return v[pre[T]^1]; } bool alter(int x) { int p; for(p=1;p<=m;p++) if(id[p][cnt[p]]==x) break; id[p][++cnt[p]]=++vid; addedge(vid,T,0); for(int i=1;i<=n;i++) addedge(i,vid,t[i][p]*cnt[p]); } void solve() { for(int i=1;i<=n;i++) alter(SPFA()); printf("%.2lf\n",1.0*res/n); } int main() { build(); solve(); return 0; }
以上是关于bzoj1070: [SCOI2007]修车的主要内容,如果未能解决你的问题,请参考以下文章