数据较大,用成Hopcroft-Karp算法更合适。
其实Hopcroft-Karp算法就是一开始通过DFS预处理出Dist标号,然后利用Dist标号实现同时查找多条最短增广路的目的。
#include <cstdlib> #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> #include <fstream> #include <iostream> #include <queue> #define rep(i, l, r) for(int i=l; i<=r; i++) #define clr(x, c) memset(x, c, sizeof(x)) #define N 3456 #define MAX 1<<30 using namespace std; int read() { int x=0, f=1; char ch=getchar(); while (ch<'0' || ch>'9') { if (ch=='-') f=-1; ch=getchar(); } while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } struct edge{int y, n;} e[N*N]; int fir[N], en; struct node{int x, y, s;} g[N]; int n, m, t, ans, k[N*2], d[N*2]; int c[N*2]; void Add(int x, int y) { en++, e[en].y=y, e[en].n=fir[x], fir[x]=en; } int Dist(int x1, int x2, int y1, int y2) { return (x2-x1)*(x2-x1)+(y1-y2)*(y1-y2); } bool Find(int x) { int o=fir[x], y=e[o].y; while (o) { if (!k[y] || (k[y] && d[x]==d[k[y]]-2 && Find(k[y]))) { k[y]=x; return true; } o=e[o].n, y=e[o].y; } return false; } int main() { int tt=0, T=read(); while (tt++ < T) { clr(fir, 0); clr(k, 0); en=ans=0; clr(c, 0); t=read(); n=read(); rep(i, 1, n) g[i].x=read(), g[i].y=read(), g[i].s=read()*t; m=read(); rep(j, 1, m) { int x=read(), y=read(); rep(i, 1, n) if (Dist(g[i].x, x, g[i].y, y) <= g[i].s*g[i].s) Add(i, j+N); } while (ans<n) { queue <int> q; bool can=true; rep(i, 1, n) if (!c[i]) q.push(i), d[i]=0; else d[i]=MAX; while (!q.empty()) { int x=q.front(), o=fir[x], y=e[o].y, dis=MAX; q.pop(); if (d[x]>dis) break; while (o) { if (!k[y]) dis=d[x]; else if (d[k[y]]==MAX) d[k[y]]=d[x]+2, q.push(k[y]); o=e[o].n, y=e[o].y; } } rep(i, 1, n) if (!c[i] && Find(i)) c[i]=true, ans++, can=false; if (can) break; } printf("Scenario #%d: %d ", tt, ans); } }