[SCOI2007]修车

题目

洛谷

做法

假设一位修理员修理的顺序分别为\(a[1],a[2]...a[n]\),时间分别为\(w[1],w[2]...w[3]\)

总等待时间为\(\sum\limits_{i=1}^n w[1]*(n-i+1)\)

\(S\)(超级源点)向n辆车连(1流量,0费用)的边,右部分是\(n*m\)个二元组\((x,y)\)表示第\(x\)个人修的第\(y\)辆车

左右连边跑最大流最小费用

My complete code

#include<bits/stdc++.h>
using namespace std;
typedef int LL;
const LL maxn=1e6+9, inf=0x3f3f3f3f;
struct node{
	LL to,nxt,f,c;
}dis[maxn];
LL n,m,num,S,T,ans;
LL head[maxn],pre_v[maxn],pre_d[maxn],flow[maxn],cost[maxn],w[101][101];
bool visit[maxn];
inline void Add(LL u,LL v,LL f,LL c){
	dis[++num]=(node){v,head[u],f,c}, head[u]=num;
}
inline LL Id(LL i,LL j){ return (i-1)*n+j; }
inline bool Spfa(){
	queue<LL> que;
	que.push(S);
	memset(flow,inf,sizeof(flow)), memset(pre_d,0,sizeof(pre_d)), memset(pre_v,0,sizeof(pre_v));
	memset(cost,inf,sizeof(cost));
	cost[S]=0;
	while(que.size()){
		LL u(que.front()); que.pop();
		visit[u]=false;
		for(LL i=head[u];i!=-1;i=dis[i].nxt){
			LL v(dis[i].to);
			if(dis[i].f && cost[v]>cost[u]+dis[i].c){
				cost[v]=cost[u]+dis[i].c;
				flow[v]=min(flow[u], dis[i].f);
				pre_v[v]=u, pre_d[v]=i;
				if(!visit[v]){
					visit[v]=true;
					que.push(v);
				}
			}
		}
	}return pre_v[T];
}
inline void Ek(){
	while(Spfa()){
		ans+=cost[T]*flow[T];
		for(LL i=T;i!=S;i=pre_v[i]){
			dis[pre_d[i]].f-=flow[T],
			dis[pre_d[i]^1].f+=flow[T];
		}
	}
	printf("%.2lf",1.0*ans/n);
}
int main(){
	cin>>m>>n;
	for(LL i=1;i<=n;++i)
	    for(LL j=1;j<=m;++j)
	        cin>>w[j][i];
	S=n*m+n+2, T=n*m+n+1;
	memset(head,-1,sizeof(head)), num=-1;
	for(LL i=1;i<=n;++i) Add(S,i,1,0), Add(i,S,0,0);
	for(LL i=1;i<=m;++i)
	    for(LL j=1;j<=n;++j){
	    	Add(n+Id(i,j),T,1,0), Add(T,n+Id(i,j),0,0);
		}
	for(LL i=1;i<=m;++i)
	    for(LL j=1;j<=n;++j){
	    	LL v(n+Id(i,j));
	    	for(LL k=1;k<=n;++k)
	    	    Add(k,v,1,w[i][k]*j),
	    	    Add(v,k,0,-w[i][k]*j);
		}
	Ek();
	return 0;
}
posted @ 2019-02-19 15:26  y2823774827y  阅读(127)  评论(0编辑  收藏  举报