BZOJ 1070 修车(费用流)

如果能想到费用流,这道题就是显然了。

要求所有人的等待平均时间最小,也就是所有人的总等待时间最小。

每辆车只需要修一次,所以s连每辆车容量为1,费用为0的边。 现在需要把每个人拆成n个点,把车和每个人的第k个点连一条容量为1,费用为cost[i][j]*k的边。

最后把每个人拆完后的点向汇点连一条容量为1,费用为0的边。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 0x7fffffff
#define T 601
using namespace std;
int n,m,cnt=1,ans,t[61][10];
int d[605],q[605],from[605],head[605];
bool mark[605];
struct edge{int from,to,next,c,v;}e[100001];
void ins(int u,int v,int w,int c)
{
    cnt++;
    e[cnt].from=u;e[cnt].to=v;
    e[cnt].next=head[u];head[u]=cnt;
    e[cnt].c=c;e[cnt].v=w;
}
void insert(int u,int v,int w,int c)
{ins(u,v,w,c);ins(v,u,0,-c);}
bool spfa()
{
    memset(mark,0,sizeof(mark));
    for(int i=0;i<=T;i++)d[i]=inf;
    int t=0,w=1;
    d[T]=0;mark[T]=1;q[0]=T;
    while(t!=w)
    {
        int now=q[t];t++;if(t==T)t=0;
        for(int i=head[now];i;i=e[i].next)
            if(e[i^1].v&&d[e[i].to]>d[now]-e[i].c)
            {
                d[e[i].to]=d[now]-e[i].c;
                if(!mark[e[i].to])
                {mark[e[i].to]=1;q[w++]=e[i].to;if(w==T)w=0;} 
            }
        mark[now]=0;    
    }
    if(d[0]==inf)return 0;
    return 1;
}
int dfs(int x,int f)
{
    if(x==T){mark[T]=1;return f;}
    int used=0,w;
    mark[x]=1;
    for(int i=head[x];i;i=e[i].next)
        if(!mark[e[i].to]&&e[i].v&&d[x]-e[i].c==d[e[i].to])
        {
            w=f-used;
            w=dfs(e[i].to,min(e[i].v,w));
            ans+=w*e[i].c;
            e[i].v-=w;e[i^1].v+=w;
            used+=w;if(used==f)return f;
        }
    return used;
}
void zkw()
{
    while(spfa())
    {
        mark[T]=1;
        while(mark[T])
        {
            memset(mark,0,sizeof(mark));
            dfs(0,inf);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
               scanf("%d",&t[i][j]);
    for(int i=1;i<=n*m;i++)
        insert(0,i,1,0);
    for(int i=n*m+1;i<=n*m+m;i++)
        insert(i,T,1,0);
    for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++)
          for(int k=1;k<=m;k++)
             insert((i-1)*m+j,n*m+k,1,t[k][i]*j);
    zkw();
    printf("%.2lf",(double)ans/m);
    return 0;
}
View Code

 

posted @ 2017-03-04 23:08  free-loop  阅读(144)  评论(0编辑  收藏  举报