poj 3686 The Windy's (KM算法)

来源:互联网 发布:电脑必备软件2016 编辑:程序博客网 时间:2024/06/06 04:27

题目描述

传送门

题目大意:n个物品,m个机器,每个机器每一时间都只能加工一个东西,加工一个东西的时间用z[i][j]表示,求每个物品最小的平均等待时间。

题解

KM算法
这道题和SCOI 修车应该是一样的。对于每个机器都拆成n个点,每个点表示加工的是倒数第t个物品,那么对于在其后面加工的t-1个物品,包括他自己本身都需要等z[i][j]的时间,所以我们从这个点向每个物品连边,边权为t*z[i][j].
因为是最小的平均等待时间,而KM是最大权完美匹配,所以我将所有的边权变成相反数即可
这道题的话其实用费用流还是很好写的。

代码

#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>#include<cmath>#define N 3200#define inf 1000000000using namespace std;int n,m,T,belong[N],pdx[N],pdy[N],cx[N],cy[N],val[N][N],slack[N];int c[N][N];int calc(int x,int y){    return (y-1)*n+x;}bool dfs(int x){    pdx[x]=1;    for (int i=1;i<=n*m;i++) {        if (pdy[i]) continue;        int gap=cx[x]+cy[i]-val[x][i];        if (!gap) {            pdy[i]=1;            if (!belong[i]||dfs(belong[i])) {                belong[i]=x;                return true;            }        } else slack[i]=min(slack[i],gap);    }    return false;}int km(){    memset(belong,0,sizeof(belong));    memset(cy,0,sizeof(cy));    for (int i=1;i<=n;i++) {        cx[i]=val[i][1];        for (int j=1;j<=n*m;j++)          cx[i]=max(val[i][j],cx[i]);    }    for (int i=1;i<=n;i++) {        for (int j=1;j<=n*m;j++) slack[j]=inf;        while (true) {          memset(pdx,0,sizeof(pdx));          memset(pdy,0,sizeof(pdy));          if (dfs(i)) break;          int d=inf;          for (int j=1;j<=n*m;j++)           if (!pdy[j]) d=min(d,slack[j]);          for (int j=1;j<=n;j++)           if (pdx[j]) cx[j]-=d;          for (int j=1;j<=n*m;j++)           if (pdy[j]) cy[j]+=d;           else slack[j]-=d;        }    }    int ans=0;    for (int i=1;i<=n*m;i++) ans+=val[belong[i]][i];    return ans;}int main(){    freopen("a.in","r",stdin);    scanf("%d",&T);    while (T--){        scanf("%d%d",&n,&m);        for (int i=1;i<=n;i++)         for (int j=1;j<=m;j++) scanf("%d",&c[i][j]);        for (int i=1;i<=n;i++)         for (int j=1;j<=n;j++)          for (int k=1;k<=m;k++)           val[i][calc(j,k)]=-j*c[i][k];        //for (int i=1;i<=n;i++,cout<<endl)        //for (int j=1;j<=n*m;j++) cout<<val[i][j]<<" ";        int ans=-km(); //cout<<ans<<endl;        double t=(double)ans*1.0/(double)n;        printf("%.6lf\n",t);    }}
0 0
原创粉丝点击