码迷,mamicode.com
首页 > 其他好文 > 详细

P2053 [SCOI2007]修车 网络流

时间:2021-01-19 12:10:04      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:P20   strong   一个   max   spfa   cpp   ret   CMF   pair   

题意:

戳这里

分析:

建不会建模,直接搬运题解的做法

我么将题意转化一下,求出每一个人对于整体答案的贡献,如果一辆车后面等了 \(k\) 个人,那么这辆车的被等待时间 就是 \(k\times T_{i,j}\) ,然后我们要做的就是为每一辆车分配一个修车工人和一个修车次序,使得任意两个车的修车工人和修车次序不会相同,然后使得总体的贡献最小,这个很费用流

具体来说就是设 \(f_(i,j)\) 表示第 \(i\) 个工人的第 \(j\) 次修理,这样我们把每一辆车 \(x\) 向这一个点连一条边,它的等待时间就是 \(j\times T(i,x)\) ,也就是这条边的费用,然后原点向每一辆车连一条边权为 \(0\) 流量为 \(1\) 的边,每一个工人的每一次修理向汇点连一条边权为 \(0\) 流量为 \(1\) 的边,这样跑一遍费用流,保证了不会有任何两辆车连向同一次修理

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second
#define inl inline
#define reg register

using namespace std;

namespace zzc
{
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch==‘-‘) f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	const int maxn = 1e3+5;
	const int maxm = 1e5+5;
	const int inf = 0x3f3f3f3f;
	int n,m,st,ed,cnt=1,ans;
	int head[maxn],dep[maxn],lst[maxn],siz[maxn],pre[maxn],flow[maxn],dis[maxn];
	bool vis[maxn];
	queue<int> q;
	
	struct edge
	{
		int to,nxt,w,cst;
	}e[maxm];
	
	void add(int u,int v,int w,int x)
	{
		e[++cnt].to=v;
		e[cnt].w=w;
		e[cnt].cst=x;
		e[cnt].nxt=head[u];
		head[u]=cnt;
	}
	
	void add_edge(int u,int v,int w,int x)
	{
		add(u,v,w,x);add(v,u,0,-x);
	}
	
	inl int id(int x,int y)
	{
		return (x-1)*n+y;
	}
	
	bool spfa()
	{
		for(int i=st;i<=ed;i++) vis[i]=false,flow[i]=inf,dis[i]=inf,pre[i]=-1;
		q.push(st);dis[st]=0;
		while(!q.empty())
		{
			int u=q.front();q.pop();
			vis[u]=false;
			for(int i=head[u];i;i=e[i].nxt)
			{
				int v=e[i].to;
				if(e[i].w&&dis[v]>dis[u]+e[i].cst)
				{
					dis[v]=dis[u]+e[i].cst;
					pre[v]=u;
					lst[v]=i;
					flow[v]=min(flow[u],e[i].w);
					if(!vis[v])
					{
						vis[v]=true;
						q.push(v);
					}
				}
			}
		}
		return pre[ed]!=-1;
	}
	
	void MCMF()
	{
		while(spfa())
		{
			int now=ed;
			ans+=dis[now]*flow[now];
			while(now!=st)
			{
				e[lst[now]].w-=flow[ed];
				e[lst[now]^1].w+=flow[ed];
				now=pre[now];
			}
		}
	}
	
	void work()
	{
		int a;
		m=read();n=read();st=0;ed=n*m+n+1;
		for(int i=1;i<=n;i++) add_edge(st,n*m+i,1,0);
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				a=read();
				for(int k=1;k<=n;k++) add_edge(n*m+i,id(j,k),1,a*k);
			}
		}
		for(int j=1;j<=m;j++) for(int k=1;k<=n;k++) add_edge(id(j,k),ed,1,0);
		MCMF();
		printf("%.2f\n",1.0*ans/n);
	}

}

int main()
{
	zzc::work();
	return 0;
}

P2053 [SCOI2007]修车 网络流

标签:P20   strong   一个   max   spfa   cpp   ret   CMF   pair   

原文地址:https://www.cnblogs.com/youth518/p/14294393.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!