bzoj1070: [SCOI2007]修车

网络流,将维修人员拆成N个,记为P(i,j),然后每辆车对P(i,j)连一条容量为1,权为j*time[i][j]的边,表示让第i个维修人员在倒数第j的位置修这辆车,于是会导到剩下的所有人多等j*time[i][j]的时间

const int N = 700;
struct Edge {
	int V, Val, Cost;
	Edge *Next, *Pair;
	Edge() {}
	Edge(int _V, int _Val, int _Cost, Edge *_Next) : 
		V(_V), Val(_Val), Cost(_Cost), Next(_Next) {}
} *Fir[N];
int S, T, Tot, Dis[N], Ans, Sum;
deque<int> Q;
bool Vis[N];
int n, m;

#define Man(x, y) (((x) - (1)) * (n) + (y))
#define Car(x) ((n) * (m) + (x))

inline void Ins(int x, int y, int val, int cost) {
	Fir[x] = new Edge(y, val, cost, Fir[x]);
	Fir[y] = new Edge(x, 0, -cost, Fir[y]);
	Fir[x]->Pair = Fir[y], Fir[y]->Pair = Fir[x];
}
inline void Input() {
	scanf("%d%d", &m, &n);
	S = n * m + n + 1, Tot = T = S + 1;
	For(i, 1, n)
		For(j, 1, m) {
			int x;
			scanf("%d", &x);
			For(k, 1, n) Ins(Man(j, k), Car(i), 1, x * k);
		}
	For(i, 1, m)
		For(j, 1, n) Ins(S, Man(i, j), 1, 0);
	For(i, 1, n) Ins(Car(i), T, 1, 0);
}

inline bool Spfa() {
	clr(Dis, 63), Q.clear();
	for(Q.pub(T), Dis[T] = 0; sz(Q);) {
		int x = Q.front(), v, t;
		Q.pof();
		for(Edge *Tab = Fir[x]; Tab != NULL; Tab = Tab->Next)
			if(Tab->Pair->Val && Dis[v = Tab->V] > (t = Dis[x] - Tab->Cost))
				(Dis[v] = t) <= Dis[sz(Q) ? Q.front() : 0] ? Q.puf(v) : Q.pub(v);
	}
	For(i, 1, Tot)
		for(Edge *Tab = Fir[i]; Tab != NULL; Tab = Tab->Next)
			Tab->Cost += Dis[Tab->V] - Dis[i];
	return Sum += Dis[S], Dis[S] < Dis[0];
}
inline int Aug(int x, int L) {
	if(x == T) return Ans += Sum * L, L;
	Vis[x] = 1;
	int N = L, v;
	for(Edge *Tab = Fir[x]; Tab != NULL; Tab = Tab->Next)
		if(Tab->Val && !Tab->Cost && !Vis[v = Tab->V]) {
			int t = Aug(v, min(Tab->Val, N));
			Tab->Val -= t, N -= t, Tab->Pair->Val += t;
			if(!N) break;
		}
	return L - N;
}

inline void Solve() {
	while(Spfa())
		for(clr(Vis, 0); Aug(S, INF) > 0; clr(Vis, 0));
	printf("%.2lf\n", (DB) Ans / n);
}

int main() {
	#ifndef ONLINE_JUDGE
	SETIO("1070");
	#endif
	Input();
	Solve();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值