【费用流】[SCOI2007]修车

链接

https://www.luogu.org/problemnew/show/P2053

大意

n 辆车 m 个人,不同的人修不同的车时间不相同,先给出他们修它们的时间,求最小平均等待时间

思路

最小平均等待时间=最小总等待时间

m 个工人分成 n × m 个人,然后把他们连向汇点,再把车连向源点,容量为1,没有代价

之后把每个人和他们可以修的车连在一起,容量为1,代价为这个人修车的顺序乘时间

之后再跑费用流就好了

代码

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define M 100000
using namespace std;int f,n,m,s,t,ans1,ans2,u,v,w,g,t1,b[1001][1001];char c;
int read()
{
    f=0;
    while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return f;
}
struct node{int next,to,w,g;}e[M<<1];
int dis[M],l[M],tot,pos[M];
bool vis[M];
void add(int u,int v,int w,int c)
{
    e[tot]={l[u],v,w,c};l[u]=tot++;
    e[tot]={l[v],u,0,-c};l[v]=tot++;
    return;
}
bool spfa()
{
    fill(dis+1,dis+1+t,50234567);
    memset(vis,0,sizeof(vis));
    queue<int>q;q.push(s);dis[s]=0;vis[s]=true;
    while(q.size())
    {
        int x=q.front();q.pop();vis[x]=true;
        for(int i=l[x];~i;i=e[i].next)
        {
            int y=e[i].to,w=e[i].g;
            if(e[i].w&&dis[y]>dis[x]+w)
            {
                dis[y]=dis[x]+w;
                pos[y]=i;
                if(!vis[y]) q.push(y),vis[y]=true;
            }
        }
        vis[x]=false;
    }
    return dis[t]<50234567;
}
void updata()
{
    int x=t;
    while(x!=s)
    {
        int i=pos[x];
        e[i].w--;
        e[i^1].w++;
        x=e[i^1].to;
    }
    ans1++;
    ans2+=dis[t];
    return;
}
void EK()
{
    while(spfa()) 
    updata();return;
}
int main()
{
    memset(l,-1,sizeof(l));
    m=read();n=read();s=0;t=n*m+n+1;
    for(int i=1;i<=n;i++) add(s,m*n+i,1,0);//车连源点
    for(int i=1;i<=n*m;i++) add(i,t,1,0);//人连汇点
    for(int j=1;j<=n;j++)
     for(int i=1,x;i<=m;i++)
     {
        x=read();
        for(int k=1;k<=n;k++) add(n*m+j,~-(i)*n+k,1,k*x);//~-i=i-1,连接这辆车和可以修这辆车的人
     }
    EK();//跑一遍费用流
    printf("%.2lf",1.0*ans2/n);//输出
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/80773521
今日推荐