1. 程式人生 > >1070. [SCOI2007]修車【費用流】

1070. [SCOI2007]修車【費用流】

med tdi lib 逆向 node void input size 小數點

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)

將M個工作人員拆成N個點
拆後的M員工的第k個裂點連某輛車,表示該車是倒數第k個被修的車
因為是倒數第k,所以費用自然要加上後面排隊的車的費用
算是一種逆向思維吧
MD n和m搞反了……找錯找了半天qwq

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define MAXN (50000+10)
#define MAXM (5000000+10)
using namespace std;
queue<int>q;
bool visit[MAXN];
int pre[MAXN];
int n,m,k,s,e=4999,Ans,Fee;
int num_edge;
int head[MAXN];
int dis[MAXN];
bool used[MAXN];
int INF;
int t[1000][1000];
struct node
{
	int to;
	int next;
	int Flow;//殘留網絡
	int Cost;
} edge[MAXM*2];

void add(int u,int v,int l,int c)
{
	edge[++num_edge].to=v;
	edge[num_edge].next=head[u];
	edge[num_edge].Flow=l;
	edge[num_edge].Cost=c;
	head[u]=num_edge;
}

bool Spfa(int s,int e)
{
	memset(pre,-1,sizeof(pre));
	memset(dis,0x7f,sizeof(dis));
	q.push(s);
	dis[s]=0;
	used[s]=true;
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		for (int i=head[x]; i!=0; i=edge[i].next)
			if (dis[x]+edge[i].Cost<dis[edge[i].to] && edge[i].Flow>0)
			{
				dis[edge[i].to]=edge[i].Cost+dis[x];
				pre[edge[i].to]=i;
				if (!used[edge[i].to])
				{
					used[edge[i].to]=true;
					q.push(edge[i].to);
				}
			}
		used[x]=false;
	}
	return (dis[e]!=INF);
}

int MCMF(int s,int e)
{
	Ans=0,Fee=0;
	while (Spfa(s,e))
	{
		int d=INF;
		for (int i=e; i!=s; i=edge[((pre[i]-1)^1)+1].to)
			d=min(d,edge[pre[i]].Flow);
		for (int i=e; i!=s; i=edge[((pre[i]-1)^1)+1].to)
		{
			edge[pre[i]].Flow-=d;
			edge[((pre[i]-1)^1)+1].Flow+=d;
		}
		Ans+=d;
		Fee+=d*dis[e];
	}
	return Fee;
}

int main()
{
	memset(&INF,0x7f,sizeof(INF));
	scanf("%d%d",&m,&n);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			scanf("%d",&t[i][j]);
	for (int i=1;i<=m*n;++i)
	{
		add(s,i,1,0);
		add(i,s,0,0);
	}
	for (int i=1;i<=n;++i)
	{
		add(m*n+i,e,1,0);
		add(e,m*n+i,0,0);
	}
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			for (int k=1;k<=n;++k)
			{
				add((j-1)*n+i,m*n+k,1,i*t[k][j]);
				add(m*n+k,(j-1)*n+i,0,-i*t[k][j]);
			}
	double ans=MCMF(s,e);
	printf("%.2lf\n",ans/n);
}

1070. [SCOI2007]修車【費用流】