• 【BZOJ】1070: [SCOI2007]修车


    【题意】m个人修n辆车,时间为给定的表格a[i][j],一个人修完一辆才能修下一辆,求每辆车修完时间的总和。m<=9,n<=60。

    【算法】最小费用最大流,二分图

    【题解】将人放左边,将车放右边构成二分图,车向T连容量为1的边即可保证每辆车只修一次。

    每个人有可能修多辆车,将每个人拆成n个点,每个点都向m辆车连边,表示这个人第 i 次修理第 j 辆车的时间。同时S向n*m个点连容量为1的边即可保证每人每次只修一辆车。

    假设一个人修车k次,那么第 i 次修车的时间会叠加到后面,计算(k-i+1)次。我们事先无法知道修车几次,不妨倒着进行。

    将边的含义改为表示这个人倒数第 i 次修理第 j 辆车的时间,然后把对别人的影响放在自己的费用上(类似于未来决策DP的套路)。

    这样倒数第k条边的费用就是x*k。因为对于同一个人和车,k增大费用增大,所以一定会优先选择k小的边,即优先填k小的点,填到多少就是修多少辆车。

    令N=n*m,复杂度O(N√N)。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=800,maxm=200000,inf=0x3f3f3f3f;
    struct edge{int from,v,flow,cost;}e[maxm];
    int n,first[maxn],d[maxn],cur[maxn],ans,m,S,T,tot=1,q[3010],t[10][70];
    bool vis[maxn];
    void insert(int u,int v,int flow,int cost)
    {
        tot++;e[tot].v=v;e[tot].flow=flow;e[tot].cost=cost;e[tot].from=first[u];first[u]=tot;
        tot++;e[tot].v=u;e[tot].flow=0;e[tot].cost=-cost;e[tot].from=first[v];first[v]=tot;
    }
    bool spfa()
    {
        memset(vis,0,T+1);
        memset(d,0x3f,4*(T+1));
        int head=0,tail=1;q[0]=T;vis[T]=1;d[T]=0;
        while(head!=tail)
         {
             int x=q[head++];if(head>3000)head=0;
             for(int i=first[x];i;i=e[i].from)
              if(e[i^1].flow&&d[x]+e[i^1].cost<d[e[i].v])
               {
                   int y=e[i].v;
                   d[y]=d[x]+e[i^1].cost;
                   if(!vis[y])
                    {
                        if(d[y]<d[q[head]]){head--;if(head<0)head=3000;q[head]=y;}
                         else{q[tail++]=y;if(tail>3000)tail=0;}
                        vis[y]=1;
                    }
               }
             vis[x]=0;
         }
        return d[S]<inf;
    }
    int dfs(int x,int a)
    {
        if(x==T||a==0)return a;
        vis[x]=1;
        int flow=0,f;
        for(int& i=cur[x];i;i=e[i].from)
         if(!vis[e[i].v]&&d[x]==e[i].cost+d[e[i].v]&&(f=dfs(e[i].v,min(a,e[i].flow)))>0)
          {
              e[i].flow-=f;
              e[i^1].flow+=f;
              ans+=e[i].cost*f;
              flow+=f;
              a-=f;
              if(a==0)break;
          }
        vis[x]=0;
        return flow;
    }
    int main()
    {
        scanf("%d%d",&m,&n);//m工人 n车 
        int x;S=0,T=n*m+n+1;
        for(int i=1;i<=n;i++)
         {
             for(int j=1;j<=m;j++)
              {
                  scanf("%d",&x);
                  t[j][i]=x;
              }
         }
        for(int i=1;i<=n*m;i++)insert(i,T,1,0);
        for(int i=n*m+1;i<=n*m+n;i++)insert(S,i,1,0);
        for(int i=1;i<=m;i++)
         for(int j=1;j<=n;j++)
          for(int k=1;k<=n;k++)
           insert(n*m+k,(i-1)*n+j,1,t[i][k]*j);//源和汇和边反过来也没事,对应上就行了。 
        ans=0;
        memset(vis,0,T+1);
        while(spfa())
         {
             for(int i=0;i<=T;i++)cur[i]=first[i];
             dfs(S,inf);
         }
        printf("%.2lf",1.0*ans/(double)n);
        return 0;
    }
    View Code
  • 相关阅读:
    maven系列--eclipse的m2插件
    eclipse安装反编译插件
    maven系列--settings.xml
    maven系列--maven常用命令
    maven系列--maven目录
    centos 常用命令
    iis7.0 发生未知 FastCGI错误,错误代码 0x8007010b 的解决办法
    git 提交的步骤
    关于PHP函数传参的注意点
    关于SQL查询语句中的LIKE模糊查询的解释
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6522778.html
Copyright © 2020-2023  润新知