题意:输入n m 代表有n个地方需要修理 m种工人 以下n行第一行两个值x y 代表仓库 后面n-1行每行前四个数代表每个地方的坐标和修理的开始时间和持续时间 后面跟上m个数 代表这个地方需要哪种工人的数量 问你最少从仓库派多少工人 工人从一个点到另一个点的时间为两点之间的欧几里得距离
思路:这题输入比较复杂绕 要求的是最少派的工人数量 其实也就是每种工人的最少数量和 因此我们可以把问题简化 分别求每一种工人的最少数量 注意到如果每个地方的工人都从仓库派出 那一定不是最优解 我们可以把在一些地方干完活的工人派到别的需要这种工人的地方 当然如果这种工人走到另一个地方 人家已经开工了也是不行的 所以就要判断如果一个地方的工人干完活了 并且走到另一个工地 那个工地还没有开工 那么我们可以直接把这个工人派到那里 省去了从仓库派工人的开销 但是这样就可以了吗? 注意到如果单纯从一个工地向另一个工地派工人是不行 因为可能人手不够 所以还得从仓库派人 这样就既从别的工地抽闲着的人 有从仓库派新人 但是题目要求从仓库派的人尽量少 这就产生一个优先级的问题 我们得先把在外边工作的工人调用光 如果还是不够 才从仓库调人 所以为了突出这个优先级 我们把每个点拆成两个点 一个代表从仓库调人 费用为1 一个代表在外干完活的人 费用为0 这样增广的时候就会先增广费用为0的边 优先级就得以体现了。。具体实现看代码吧。。这题题解感觉在讲故事。。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
#define REP( i, a, b ) for( int i = a; i < b; i++ )
#define FOR( i, a, b ) for( int i = a; i <= b; i++ )
#define CLR( a, x ) memset( a, x, sizeof a )
#define CPY( a, x ) memcpy( a, x, sizeof a )
const int maxn = 300;
const int maxe = 50000;
const int INF = 0x3f3f3f3f;
struct Edge{
int v, c, f, w;
int next;
Edge() {}
Edge(int v, int c, int f, int w, int next) : v(v), c(c), f(f), w(w), next(next) {}
};
struct MCMF{
int n, s, t;
int d[maxn], cur[maxn], f[maxn];
int Head[maxn], cntE;
int Q[maxn], head, tail, inq[maxn];
int flow;
long long cost;
Edge edge[maxe];
void Init(int n){
this -> n = n;
cntE = 0;
CLR(Head, -1);
}
void Add(int u, int v, int c, int w){
edge[cntE] = Edge(v, c, 0, w, Head[u]);
Head[u] = cntE++;
edge[cntE] = Edge(u, 0, 0, -w, Head[v]);
Head[v] = cntE++;
}
int Spfa(){
head = tail = 0;
CLR(d, INF);
CLR(inq, 0);
Q[tail++] = s;
f[s] = INF;
cur[s] = -1;
d[s] = 0;
while(head != tail){
int u = Q[head++];
if(head == maxn) head = 0;
inq[u] = 0;
for(int i = Head[u]; ~i; i = edge[i].next){
int v = edge[i].v;
if(edge[i].c > edge[i].f && d[v] > d[u] + edge[i].w){
f[v] = min(f[u], edge[i].c - edge[i].f);
d[v] = d[u] + edge[i].w;
cur[v] = i;
if(!inq[v]){
if(d[v] < d[Q[head]]){
if(head == 0) head = maxn;
Q[--head] = v;
}
else{
Q[tail++] = v;
if(tail == maxn) tail = 0;
}
inq[v] = 1;
}
}
}
}
if(d[t] == INF) return 0;
flow += f[t];
cost += (long long)f[t] * (long long)d[t];
for(int i = cur[t]; ~i; i = cur[edge[i^1].v]){
edge[i].f += f[t];
edge[i^1].f -= f[t];
}
return 1;
}
long long Mcmf(int s, int t){
this -> s = s;
this -> t = t;
flow = 0;
cost = 0;
while(Spfa());
return cost;
}
}solver;
pair<int, int> pi[maxn];
int need[maxn][maxn];
int p[maxn], b[maxn];
int dis[maxn][maxn];
int dist(int i, int j){
return (pi[i].first - pi[j].first) * (pi[i].first - pi[j].first) +
(pi[i].second - pi[j].second) * (pi[i].second - pi[j].second);
}
void DIS(int n){
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)
dis[i][j] = dis[j][i] = dist(i, j);
}
void solve(){
int n, m;
scanf("%d%d", &n, &m);
memset(need, 0, sizeof(need));
memset(p, 0, sizeof(p));
memset(b, 0, sizeof(b));
scanf("%d%d", &pi[1].first, &pi[1].second);
b[1] = 0, p[1] = 0;
for(int i = 2; i <= n; i++){
scanf("%d%d", &pi[i].first, &pi[i].second);
scanf("%d%d", &b[i], &p[i]);
for(int j = 1; j <= m; j++) scanf("%d", &need[i][j]);
}
DIS(n);
long long ans = 0LL;
int S = 1, T = n * 2 + 1;
for(int i = 1; i <= m; i++){
solver.Init(T + 1);
for(int j = 2; j <= n; j++){
solver.Add(S, j, need[j][i], 1);
solver.Add(S, j + n, need[j][i], 0);
solver.Add(j, T, need[j][i], 0);
}
for(int j = 1; j <= n; j++)
for(int k = 1; k <= n; k++)if(k != j && k != 1){
if(sqrt(1.0 * dis[j][k]) + 1.0 * b[j] + 1.0 * p[j] <= b[k])
solver.Add(j + n, k, need[j][i], 0);
}
solver.Add(0, S, INF, 0);
ans += solver.Mcmf(S, T);
}
printf("%I64d\n", ans);
}
int main()
{
int T;
scanf("%d", &T);
while(T--) solve();
return 0;
}