P2053 [SCOI2007]修车(逆向思维分层建图)

得 先 把 题 意 转 化 一 下 , 否 则 无 法 建 图 得先把题意转化一下,否则无法建图 ,

为 啥 没 办 法 建 图 ? 因 为 每 个 师 傅 修 每 辆 车 的 代 价 不 是 为啥没办法建图?因为每个师傅修每辆车的代价不是 ?定值

不 是 定 值 , 就 想 办 法 变 成 定 值 。 不是定值,就想办法变成定值。 ,

考 虑 某 个 师 傅 一 次 修 车 a 1 , a 2 , a 3 , a 4 考虑某个师傅一次修车a_1,a_2,a_3,a_4 a1,a2,a3,a4

那 么 a 1 的 等 待 时 间 是 a 1 那么a_1的等待时间是a_1 a1a1

a 2 的 等 待 时 间 是 a 1 + a 2 a_2的等待时间是a_1+a_2 a2a1+a2

a 3 的 等 待 时 间 是 a 1 + a 2 + a 3 a_3的等待时间是a_1+a_2+a_3 a3a1+a2+a3

a 4 的 等 待 时 间 是 a 1 + a 2 + a 3 + a 4 a_4的等待时间是a_1+a_2+a_3+a_4 a4a1+a2+a3+a4

设 某 个 师 傅 修 了 x 辆 车 设某个师傅修了x辆车 x

最 后 修 的 车 的 代 价 只 需 要 在 原 来 基 础 上 乘 1 最后修的车的代价只需要在原来基础上乘1 1

倒 数 第 二 次 修 车 的 代 价 只 需 要 在 原 来 的 基 础 上 乘 2 倒数第二次修车的代价只需要在原来的基础上乘2 2

. . . . . . . . . . . . . . . . . . . . . . ...................... ......................

于 是 把 m 个 师 傅 分 成 n 层 于是把m个师傅分成n层 mn

第 i 层 表 示 修 倒 数 第 i 辆 车 的 师 傅 , 那 么 代 价 乘 以 i 第i层表示修倒数第i辆车的师傅,那么代价乘以i ii,i

每 层 的 每 个 师 傅 向 每 一 辆 车 连 边 即 可 每层的每个师傅向每一辆车连边即可

跑 最 小 费 用 最 大 流 , 对 于 每 个 师 傅 而 言 一 定 是 依 次 选 择 跑最小费用最大流,对于每个师傅而言一定是依次选择 ,

修 倒 数 第 1 辆 车 , 修 倒 数 第 2 辆 车 , 实 际 上 这 也 是 连 续 的 修倒数第1辆车,修倒数第2辆车,实际上这也是连续的 1,2,

#include 
using namespace std;
const int maxn=2e5+10;
const int inf=1e9; 
int n,m,s,t,c[509][509];
struct edge{
	int to,nxt,flow,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w,int flow){
	d[++cnt]=(edge){v,head[u],flow,w},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],0,-w},head[v]=cnt;
}
int dis[maxn],mincost,vis[maxn],pre[maxn],flow[maxn];
bool spfa()
{
	for(int i=0;i<=t;i++)	dis[i]=inf,vis[i]=0;
	dis[s]=0,flow[s]=inf;
	queueq; q.push( s );
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v=d[i].to;
			if( d[i].flow&&dis[v]>dis[u]+d[i].w )
			{
				dis[v]=dis[u]+d[i].w;
				flow[v]=min(flow[u],d[i].flow);
				pre[v]=i;
				if(	!vis[v] )	vis[v]=1,q.push( v );
			}
		}
	}
	return dis[t]!=inf;
}
int dinic()
{
	while( spfa() )
	{
		int x=t;
		mincost+=flow[t]*dis[t];
		while( x!=s )
		{
			int i=pre[x];
			d[i].flow-=flow[t];
			d[i^1].flow+=flow[t];
			x=d[i^1].to;
		}
	}
}
int main()
{
	cin >> m >> n;//m位技术人员,n位车主
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
		cin >> c[i][j];
	s=0,t=n*m+n+1;
	for(int i=1;i<=n*m;i++)	add(s,i,0,1);//源点连向每个师傅
	for(int i=1;i<=m;i++)//枚举每个师傅 
	for(int j=1;j<=n;j++)//枚举每个车 
	for(int k=1;k<=n;k++)//枚举每个时刻 
	{
		int id=(k-1)*m+i;//第k层图,每层图有m个师傅
		add(id,j+n*m,c[j][i]*k,1);	
	} 
	for(int i=1;i<=n;i++)	add(n*m+i,t,0,1);
	dinic();
	printf("%.2lf",double(mincost)/(n*1.0) );
}

你可能感兴趣的:(网络流24题)