思路:这题我在下午重现的时候就用的费用流做,可是各种悲催的超时,只是我一开始的那种建图方式多了一个二分查找。
戏剧性的是,求距离的返回值写成int型了,CodeBlock编译器又没有警告,然后就WA啊WA,AC率一下就被拉低了。
当然,对每种工人分别建图是不变的,因为每种工人互不影响。
后来想到了一个较好的建图方式,将每个点拆成3个点,i,i+n,i+2*n。
1号点就是仓库,也就是超级源点,3*n+1号点为超级汇点。
由1号点想每个i建一条流量为ty[i][j],费用为1的边。表示每次增加流量,人数就增加。
由i向i+2*n建一条流量为ty[i][j],费用为0的边。
由i+2*n向汇点建一条流量为ty[i][j],费用为0的边。
由1向每个i+n建一条流量为ty[i][j],费用为0的边。
对i号点,寻找开始时间sta[k]满足b[i]+p[i]+d[i][j]的点k,然后由i+n向k+2*n建一条流量为ty[i][j],费用为0的边。
这样,如果i号点的工人能到k号点工作,那么k号点的k+2*n到3*n+1的流量就会减少ty[i][j]。
#include<iostream> #include<cstring> #include<cstring> #include<cmath> #include<cstdio> #define inf 100000000 using namespace std; const int Maxn = 600; struct Edge{ int v; int val; int cost; int next; }edge[Maxn*600]; struct Point{ double x,y; }p[Maxn]; int head[Maxn],n,m,k; int e; int dis[Maxn],pre[Maxn], pos[Maxn],sta[Maxn],en[Maxn],ty[Maxn][20],flow; int que[Maxn*600]; double d[Maxn][Maxn]; bool vis[Maxn]; void add(int u, int v, int val, int cost) { edge[e].v = v; edge[e].val = val; edge[e].cost = cost; edge[e].next = head[u]; head[u] = e++; edge[e].v = u; edge[e].val = 0; edge[e].cost = -cost; edge[e].next = head[v]; head[v] = e++; } double DIS(Point a,Point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void init() { memset(head,-1,sizeof(head)); e=0; } bool spfa(int s, int t) { int i; memset(pre, -1, sizeof(pre)); memset(vis, 0, sizeof(vis)); int Head, tail; Head = tail = 0; for(i = 0; i < Maxn; i++) dis[i] = inf; que[tail++] = s; pre[s] = s; dis[s] = 0; vis[s] = 1; while(Head != tail) { int now = que[Head++]; vis[now] = 0; for(i=head[now]; i != -1; i = edge[i].next) { int adj = edge[i].v; if(edge[i].val > 0 && dis[now] + edge[i].cost < dis[adj]) { dis[adj] = dis[now] + edge[i].cost; pre[adj] = now; pos[adj] = i; if(!vis[adj]) { vis[adj] = 1; que[tail++] = adj; } } } } return pre[t] != -1; } int MinCostFlow(int s, int t) { int i; int cost = 0; flow = 0; while(spfa(s, t)) { int f = 100000000; for(i = t; i != s; i = pre[i]) if (edge[pos[i]].val < f) f = edge[pos[i]].val; flow += f; cost += dis[t] * f; for(i = t; i != s; i = pre[i]) { edge[pos[i]].val -= f; edge[pos[i] ^ 1].val += f; } } return cost; } void build(int type) { int i,j; init(); for(i=2;i<=n;i++){ add(1,i,ty[i][type],1); add(i,i+2*n,ty[i][type],0); add(1,i+n,ty[i][type],0); add(i+2*n,3*n+1,ty[i][type],0); for(j=2;j<=n;j++){ if(sta[i]+en[i]+d[i][j]<=sta[j]){ add(i+n,j+2*n,ty[i][type],0); } } } } int solve() { int i,j,u,v; int ans=0; for(i=1;i<=m;i++){ build(i); ans+=MinCostFlow(1,3*n+1); } return ans; } int main() { int i,j,u,v,c,t; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); scanf("%lf%lf",&p[1].x,&p[1].y); for(i=2;i<=n;i++){ scanf("%lf%lf%d%d",&p[i].x,&p[i].y,&sta[i],&en[i]); for(j=1;j<=m;j++){ scanf("%d",&ty[i][j]); } } for(i=1;i<=n;i++){ for(j=i+1;j<=n;j++){ d[i][j]=d[j][i]=DIS(p[i],p[j]); } } printf("%d ",solve()); } return 0; }