BZOJ 1070 费用流

来源:互联网 发布:ipad怎么装windows系统 编辑:程序博客网 时间:2024/04/29 12:58

    对于这类题我们往往进行拆点处理,不过这道题比较麻烦的是一个人修不同车花费的时间不同,这就无法得到第i个人修第j次时对答案的贡献,因为我们不知道这个人一共修几辆车,也就无法得到他修第j次时,后面的车一共等了多久。所谓正难则反,我们考虑将点拆成表示第i个人修倒数第j辆车,这样我们就知道他修这辆车时,总等待时间为j*a,a是他修这辆车的时间。这样我们就可以通过这样的拆点方式来建立最小费用最大流模型,从而得到答案。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 1005#define maxm 100005#define INF 1000000000int pre[maxm],other[maxm],last[maxn],cost[maxm],cap[maxm];int q[maxm+5],d[maxn],next[maxn],n,m,sum;bool vis[maxn];int S,T,l;void connect(int x,int y,int z,int c){pre[l]=last[x];last[x]=l;other[l]=y;cap[l]=z;cost[l]=c;l++;swap(x,y);pre[l]=last[x];last[x]=l;other[l]=y;cap[l]=0;cost[l]=-c;l++;}bool spfa(){memset(d,127,sizeof d);memset(next,-1,sizeof next);q[1]=S;d[S]=0;int h=0,t=1;while (h!=t) {h=h%maxm+1;int u=q[h];vis[u]=0;for (int p=last[u];p!=-1;p=pre[p]) {if (cap[p]<=0) continue;int v=other[p];if (d[v]>d[u]+cost[p]) {next[v]=p;d[v]=d[u]+cost[p];if (!vis[v]) {t=t%maxm+1;q[t]=v;vis[v]=1;}}}}return d[T]<INF;}int MCMF(void){int M=0,flow=INF;for (int p=next[T];p!=-1;p=next[other[p^1]]) flow=min(flow,cap[p]);for (int p=next[T];p!=-1;p=next[other[p^1]]) {cap[p]-=flow;cap[p^1]+=flow;M+=cost[p];}return M;}int main(){scanf("%d%d",&m,&n);S=0;T=n*m+n+1;memset(last,-1,sizeof last);for (int i=1;i<=n;i++) {connect(m*n+i,T,1,0);for (int j=1;j<=m;j++) {int a;scanf("%d",&a);for (int k=1;k<=n;k++)connect((j-1)*n+k,i+m*n,1,a*k);}}for (int i=1;i<=m;i++)for (int k=1;k<=n;k++) connect(S,(i-1)*n+k,1,0);while (spfa()) sum+=MCMF();double ans=(double)sum/n;printf("%.2lf\n",ans);return 0;}


0 0
原创粉丝点击