zoukankan      html  css  js  c++  java
  • BZOJ 1070: [SCOI2007]修车

    1070: [SCOI2007]修车

    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

    ——我是愉快的分隔符——

    本题一眼的费用流。
    考虑每个工人,若工人修某辆车,则等待总时间是这个工人的修理时间*剩余车辆数。
    所以可以将每辆车与源点连边,流量为1,费用为0,控制每辆车只被修一次。
    每个工人拆成N个点,分别与汇点相连,流量为1,费用为0,控制工人在同一时间修理一次;
    每辆车和每个工人对应的时间相连,流量为1,费用为车子的倒数数*修理时间。
    一边费用流直接出。

    下面是代码:

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    int m,n;
    int t[65][10];
    
    const int Maxm=100000;//最大边数 
    const int Maxn=1000;//最大点数 
    struct Edge{
    	Edge(){};
    	Edge(int a,int b,int c,int d,int e){
    		u=a;
    		v=b; 
    		f=c;
    		w=d;
    		nxt=e;
    	}
    	int u,v,f,w,nxt;//U当前点 V来自点 F最大流量 W费用 NXT下一个点 
    };
    int cnt=1;//边计数
    int inf=2147483647;//无限大 
    int g[Maxn+10];//点的边集的开始序号 
    Edge e[Maxm+10];//边集 
    int dist[Maxn+10];//费用 
    int src,sink;//源点与汇点 
    queue<int> que;//宽搜队列 
    bool inque[Maxn+10];//宽搜判断标志 
    int from[Maxn+10];//来源->用于计算费用 
    int ans=0;//存储最小费用 
    
    inline int remin(int a,int b){
    	return a<b?a:b;
    }
    
    inline void insert(int u,int v,int f,int w){
    	cnt++;
    	e[cnt]=Edge(u,v,f,w,g[u]);
    	g[u]=cnt;//增加一个边 
    } 
    
    inline void addEdge(int u,int v,int f,int w){
    	insert(u,v,f,w);//插入正边 
    	insert(v,u,0,-w);//插入反边 
    }
    
    inline bool spfa(){
    	while (!que.empty()) que.pop();//清空队列 
    	for (int i=0;i<=sink;i++) dist[i]=inf;//清最大值
    	que.push(src);
    	inque[src]=true;
    	dist[src]=0;//加入源点
    	//标准SPFA计算最短路 流量作为通行标准,费用作为路径长度 
    	while(!que.empty()){
    		int now=que.front();
    		que.pop();
    		for (int i=g[now];i;i=e[i].nxt){
    			if (e[i].f!=0 && dist[e[i].v]>dist[now]+e[i].w){
    				dist[e[i].v]=dist[now]+e[i].w;
    				from[e[i].v]=i;
    				if (inque[e[i].v]==false){
    					inque[e[i].v]=true;
    					que.push(e[i].v);
    				}
    			}
    		}
    		inque[now]=false;
    	} 
    	if (dist[sink]==inf) return false;//无法在增广 
    	return true;
    }
    
    inline void calcAns(){
    	int minflow=inf;
    	for (int i=from[sink];i;i=from[e[i].u]) minflow=remin(minflow,e[i].f);//寻找整条路经的流量 
    	for (int i=from[sink];i;i=from[e[i].u]) {
    		e[i].f-=minflow;//正边减流量 
    		e[i^1].f+=minflow;//反边加流量 
    		ans+=e[i].w*minflow;//计算费用 
    	}
    }
    
    inline void minCostFlow(){
    	while(spfa())calcAns();
    }
    
    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]);
    	src=0;//设置源点 
    	sink=1001;//设置汇点 
    	//建边 
    	for(int i=1;i<=n*m;i++)
            addEdge(src,i,1,0);
        for(int i=n*m+1;i<=n*m+m;i++)
            addEdge(i,sink,1,0);
        for(int i=1;i<=n;i++)
           for(int j=1;j<=m;j++)
              for(int k=1;k<=m;k++)
                 addEdge((i-1)*m+j,n*m+k,1,t[k][i]*j);
    	minCostFlow();
    	printf("%.2lf",(double)ans/m);
    	return 0;
    }




  • 相关阅读:
    金蝶数据库执行语句
    金蝶 更新价格分录表触发器
    金蝶触发器,生成条码信息
    SQL从中文中获取拼音首字母
    C语言 typedef用法
    这姑娘漂亮不,说实话,有糖吃
    条码开发的意义在哪里
    ERP开发,重点不在功能
    金蝶出入库数据库表里加字段后出现的问题解决
    解决金蝶未检测到K/3许可文件,并且该账套已超过演示版期限问题
  • 原文地址:https://www.cnblogs.com/WNJXYK/p/4063967.html
Copyright © 2011-2022 走看看