题意

给定一个有向图,在这个图上的某些点上放伞兵,可以使伞兵可以走到图上所有的点。且每个点只被一个伞兵走一次。问至少放多少伞兵。

思路

裸的最小路径覆盖。

°最小路径覆盖

【路径覆盖】在一个有向图G(V, E<u,v>)中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每条路径就是一个弱连通子集. 【最小路径覆盖】最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖. 【解法 && 路径覆盖与二分图匹配的关系】最小路径覆盖=|V|-最大匹配数,其中最大匹配数的求法是把G中的每个顶点pi分成两个顶点pi'与pi'',如果在p中存在一条pi到pj的边,那么在二分图G'中就有一条连接pi'与pj''的无向边;这里pi' 就是p中pi的出边,pj''就是p中pj 的一条入边;

代码

[cpp] #include #include #include #include #include #include #include #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, m) for (int i = begin; i < begin+m; i ++) using namespace std; const int MAXV = 1005; //N1+N2 vector adj[MAXV]; struct MaximumMatchingOfBipartiteGraph{ int vn; void init(int n){ //二分图两点集点的个数 vn = n; for (int i = 0; i <= vn; i ++) adj[i].clear(); } void add_uedge(int u, int v){ adj[u].push_back(v); adj[v].push_back(u); } bool vis[MAXV]; int mat[MAXV]; //记录已匹配点的对应点 bool cross_path(int u){ for (int i = 0; i < (int)adj[u].size(); i ++){ int v = adj[u][i]; if (!vis[v]){ vis[v] = true; if (mat[v] == 0 || cross_path(mat[v])){ mat[v] = u; mat[u] = v; return true; } } } return false; } int hungary(){ MEM(mat, 0); int match_num = 0; for (int i = 1; i <= vn; i ++){ MEM(vis, 0); if (!mat[i] && cross_path(i)){ match_num ++; } } return match_num; } void print_edge(){ for (int i = 1; i <= vn; i ++){ for (int j = 0; j < (int)adj[i].size(); j ++){ printf("u = %d v = %d\n", i, adj[i][j]); } } } }match; struct rides{ int begintime, endtime; int x1, y1, x2, y2; }r[MAXV>>1]; int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int t; scanf("%d", &t); while(t --){ int n; scanf("%d", &n); match.init(2*n); REP(i, 0, n){ int hour, minute; scanf("%d:%d %d %d %d %d", &hour, &minute, &r[i].x1, &r[i].y1, &r[i].x2, &r[i].y2); r[i].begintime = hour * 60 + minute; r[i].endtime = r[i].begintime + abs(r[i].x2 - r[i].x1) + abs(r[i].y2 - r[i].y1); } REP(i, 0, n) REP(j, 0, n){ if (i == j) continue; if (abs(r[i].x2 - r[j].x1) + abs(r[i].y2 - r[j].y1) < (r[j].begintime - r[i].endtime)){ match.add_uedge(i, j+n); } } printf("%d\n", n-match.hungary()); } return 0; } [/cpp]
举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG