博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

BZOJ.1070.[SCOI2007]修车(费用流SPFA)

题目链接

/*
神tm看错题*2。。
假如人员i依次维修W1,W2,...,Wn,那么花费的时间是 W1 + W1+W2 + W1+W2+W3... = W1*n + W2*(n-1) + ... + Wn*1
即车j是第a个修的 产生的贡献是(n-a+1)*t[i][j] 
车j是倒数第a个修的 产生的贡献是a*t[i][j] 
每个人员都是这样。所以可以把前边的常数处理下,把一个人员拆成n个表示n个阶段(i阶段表示倒数第i个修),每辆车分别连即可 

注: 点的编号 & 可入q[]多次。。别弄错。。
*/
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define gc() getchar()
const int N=700,M=50000,INF=0x3f3f3f3f;

int n,m,src,des,Enum,H[N],fr[M<<1],to[M<<1],nxt[M<<1],cap[M<<1],cost[M<<1];
int dis[N],pre[N];
std::queue<int> q;
bool inq[N];

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
inline void AddEdge(int u,int v,int c)
{
	to[++Enum]=v, nxt[Enum]=H[u], fr[Enum]=u, cap[Enum]=1, cost[Enum]=c, H[u]=Enum;
	to[++Enum]=u, nxt[Enum]=H[v], fr[Enum]=v, cap[Enum]=0, cost[Enum]=-c, H[v]=Enum;
}
bool SPFA()
{
	memset(dis,0x3f,sizeof dis);
	dis[src]=0, q.push(src);
	while(!q.empty())
	{
		int x=q.front();q.pop();
		inq[x]=0;
		for(int i=H[x];i;i=nxt[i])
			if(cap[i] && dis[to[i]]>dis[x]+cost[i])
			{
				dis[to[i]]=dis[x]+cost[i], pre[to[i]]=i;
				if(!inq[to[i]]) inq[to[i]]=1, q.push(to[i]);
			}
	}
	return dis[des]<INF;
}
int MCMF()
{
	int c=0;
//	for(int i=des;i!=src;i=fr[pre[i]])
//		mn=std::min(mn,cap[pre[i]]);
	for(int i=des;i!=src;i=fr[pre[i]])
		--cap[pre[i]],++cap[pre[i]^1],c+=cost[pre[i]];
	return c;
}

int main()
{
	Enum=1;
	m=read(),n=read();
	for(int t,i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
		{
			t=read();
			for(int k=1;k<=n;++k)
				AddEdge(i,n*(j+1)-k+1,k*t);
		}
	src=0, des=n*(m+1)+1;
	for(int i=1;i<=n;++i) AddEdge(src,i,0);
	for(int i=n+1;i<des;++i) AddEdge(i,des,0);
	int res=0;
	while(SPFA()) res+=MCMF();
	printf("%.2lf",1.0*res/n);

	return 0;
}
posted @ 2018-02-06 09:27  SovietPower  阅读(137)  评论(0编辑  收藏  举报