zoukankan      html  css  js  c++  java
  • BZOJ1070 [SCOI2007]修车

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

     

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

     

     

    Description

      同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同
    的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最
    小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。

    Input

      第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人
    员维修第i辆车需要用的时间T。

    Output

      最小平均等待时间,答案精确到小数点后2位。

    Sample Input

    2 2
    3 2
    1 4

    Sample Output

    1.50

    HINT

     

    数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)

     

     

    正解:网络流、费用流

    解题报告:

      费用流建模好题。

      不妨设工人i修第j台车的时间为tim(i,j),则

      并把每个工人拆成n个,对于工人i的第j个点表示工人i倒数第j个修的处理点,记为(i,j);

      S向每个人连容量为1、边权为0的边,对于第i个人,向(j,k)连容量为1、边权tim[j][i]*k的边,最小费用最大流即为答案。

      考虑这样做的正确性,因为我们难以确定一个点被其他点的“影响程度”,不妨换个思路,考虑当前点对于别的点造成的影响,很容易发现,如果当前车在当前工人这里倒数第k个修理,那么对全局产生的贡献就是k*tim,这样一来就可以直接处理每个点的贡献,直接上费用流。

     

    //It is made by ljh2000
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    using namespace std;
    typedef long long LL;
    const int inf = (1<<29); 
    const int MAXN = 50011;
    int n,m,tim[12][100],S,T,first[MAXN],ecnt,ans,dis[MAXN],dui[MAXN],head,tail,vis[MAXN],pre[MAXN],pp[MAXN];
    struct edge{int next,f,w,to;}e[MAXN*2];
    inline void link(int x,int y,int F,int z){
    	e[++ecnt].next=first[x]; e[ecnt].to=y; e[ecnt].f=F; e[ecnt].w=z; first[x]=ecnt;
    	e[++ecnt].next=first[y]; e[ecnt].to=x; e[ecnt].f=0; e[ecnt].w=-z; first[y]=ecnt;
    }
    
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline bool SPFA(){
    	head=tail=0; for(int i=1;i<=T;i++) dis[i]=inf,vis[i]=0,pre[i]=pp[i]=-1; dis[S]=0; dui[++tail]=S; vis[S]=1; int u;
    	while(head<tail) {
    		head++;	u=dui[head]; vis[u]=0;//!!!
    		for(int i=first[u];i;i=e[i].next) {
    			if(e[i].f==0) continue;	int v=e[i].to; 
    			if(dis[v]>dis[u]+e[i].w) {
    				dis[v]=dis[u]+e[i].w;
    				pre[v]=u;
    				pp[v]=i;
    				if(vis[v]==0) {
    					vis[v]=1;
    					dui[++tail]=v;
    				}
    			}
    		}
    	}
    	if(dis[T]==inf) return false; int ff=inf;
    	for(u=T;u!=S;u=pre[u]) ff=min(ff,e[pp[u]].f);
    	for(u=T;u!=S;u=pre[u]) ans+=ff*e[pp[u]].w,e[pp[u]].f-=ff,e[pp[u]^1].f+=ff;
    	return true;
    }
    
    inline void work(){
    	m=getint(); n=getint();	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) tim[j][i]=getint();
    	ecnt=1; S=n*m+n+1; T=S+1; for(int i=1;i<=n;i++) link(S,n*m+i,1,0);
    	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=1;k<=n;k++) link(n*m+i,(j-1)*n+k,1,tim[j][i]*k);				
    	for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) link((i-1)*n+j,T,1,0);//!!!
    	ans=0; while(SPFA()) ;  
    	double out=ans; out/=(double)n;
    	printf("%.2lf",out);
    }
    
    int main()
    {
        work();
        return 0;
    }
    

      

  • 相关阅读:
    hihoCoder #1062 : 最近公共祖先·一
    hihoCoder #1050 : 树中的最长路
    hihoCoder #1049 : 后序遍历
    108 Convert Sorted Array to Binary Search Tree 将有序数组转换为二叉搜索树
    107 Binary Tree Level Order Traversal II 二叉树的层次遍历 II
    106 Construct Binary Tree from Inorder and Postorder Traversal 从中序与后序遍历序列构造二叉树
    105 Construct Binary Tree from Preorder and Inorder Traversal 从前序与中序遍历序列构造二叉树
    104 Maximum Depth of Binary Tree 二叉树的最大深度
    102 Binary Tree Level Order Traversal 二叉树的层次遍历
    101 Symmetric Tree 判断一颗二叉树是否是镜像二叉树
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6204363.html
Copyright © 2011-2022 走看看