首先谈谈对最小路径覆盖核心函数的理解:每次从u出发寻找扩增点,若v已被其他点h扩增,则递归令h重新扩增另一个点,并把v的父节点指向h
int getNext(int u) { for (int i = head[u], v; i!= -1; i=next[i]) { if ( !vis[v=to[i]]) { vis[v] = 1; if (fa[v] == -1 || getNext(fa[v])) { fa[v] = u; return 1; } } } return 0; }
图论(线段交叉),最小路径覆盖。。。。
貌似hdu的编译器有bug
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; #define MAXN 310 #define MAXM 100000 int n, m, p; struct node { int x, y; }data[MAXN]; int seq[MAXN]; double dis[MAXN][MAXN]; int head[MAXN], to[MAXM], next[MAXM], szEdge; int vis[MAXN], fa[MAXN]; void add(int u, int v) { to[szEdge] = v; next[szEdge] = head[u]; head[u] = szEdge++; } int getNext(int u) { for (int i = head[u], v; i!= -1; i=next[i]) { if ( !vis[v=to[i]]) { vis[v] = 1; if (fa[v] == -1 || getNext(fa[v])) { fa[v] = u; return 1; } } } return 0; } inline double getDis(int i, int j) { return sqrt( (double)(data[i].x-data[j].x)*(data[i].x-data[j].x) + (double)(data[i].y-data[j].y)*(data[i].y-data[j].y)); } inline int getCross(node &n0, node &n1, node &n2) { return (n1.x-n0.x)*(n2.y-n0.y) - (n1.y-n0.y)*(n2.x-n0.x); } int isCross(node a1, node a2, node b1, node b2) { int d1 = getCross(a1,a2,b1), d2 = getCross(a1,a2,b2), d3 = getCross(b1,b2,a1), d4 = getCross(b1,b2,a2); if(((d1>0&&d2<0)||(d1<0&&d2>0))&&((d3>0&&d4<0)||(d3<0&&d4>0))) return 1; return 0; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif // ONLINE_JUDGE int t, i; scanf("%d", &t); while (t--) { scanf("%d%d%d", &n, &m, &p); int cnt = n + 2*m; for ( i = 1; i<= n; ++i) scanf("%d%d", &data[i].x, &data[i].y); for (i = n+1; i<= cnt; ++i) scanf("%d%d", &data[i].x, &data[i].y); for (i = 1; i<= n; ++i) scanf("%d", &seq[i]); /// 初始化距离 for (i = 1; i<= cnt; ++i) { for (int j = i; j<= cnt; ++j) { if (i == j) dis[i][j] = 0.0; else { dis[j][i] = getDis(i,j); dis[i][j] = dis[j][i]; } } } /// 判断交叉 for (i = 1; i<= cnt ; ++i) { for (int j = i+1; j<= cnt; ++j) { if (dis[i][j] < 0.0) continue; for (int k = n+1; k <= cnt; k+=2) { if (isCross(data[i],data[j],data[k],data[k+1])) { dis[i][j] = dis[j][i] = -1; break; } } } } /// floyd for (i = 1; i<= cnt; ++i) for (int j = 1; j<= cnt; ++j) if (dis[j][i] != -1 ) for (int k = 1; k<= cnt; ++k) if (dis[i][k] != -1) { if (dis[j][k] == -1) dis[j][k] = dis[k][j] = dis[j][i] + dis[i][k]; else if (dis[j][k] > dis[j][i] + dis[i][k]) dis[j][k] = dis[k][j] = dis[j][i] + dis[i][k]; } double l = 0.0, r = 40000.0 , mid; const double inf = 1e-6; while (r-l > inf) { mid = (l+r)/2.0; memset(head, -1, sizeof head); memset(fa, -1, sizeof fa); szEdge = 0; for (i = 1; i<= n; ++i) for (int j = i+1; j<= n; ++j) if (dis[seq[i]][seq[j]] != -1 && dis[seq[i]][seq[j]] <= mid) add(seq[i], seq[j]); int tp = 0; /// 最小路径覆盖 for (i = 1; i<= n; ++i) { memset(vis, 0, sizeof vis); if (getNext(i)) ++tp; } if (n-tp <= p) r = mid; else l = mid; } printf("%.2lf\n", (l+r)/2.0); } return 0; }
匈牙利算法,但核心与最小路径覆盖一致,都是逐渐扩增
#include <stdio.h> #include <vector> #include <string.h> #include <math.h> using namespace std; #define MAXN 1005 int fa[MAXN], vis[MAXN]; struct _node { int x, y; } dm[MAXN], dn[MAXN]; vector<int> nxt[MAXN]; int test ( int i, int j ) { _node a = dn[i], b = dm[j]; if ( a.x == b.x && a.y == b.y ) { return 1; } if ( a.x + 1 == b.x && a.y == b.y ) { return 1; } if ( a.x == b.x && a.y == b.y + 1 ) { return 1; } if ( a.x + 1 == b.x && a.y == b.y + 1 ) { return 1; } return 0; } int fnd ( int u ) { for ( unsigned int i = 0; i < nxt[u].size(); ++i ) { int v = nxt[u][i]; if ( vis[v] ) { continue; } vis[v] = 1; if ( fa[v] == -1 || fnd ( fa[v] ) ) { fa[v] = u; return 1; } } return 0; } int main() { #ifdef __GNUC__ freopen ( "in.txt", "r", stdin ); //freopen ( "out.txt", "w", stdout ); #endif // __GNUC__ int n, m; while ( scanf ( "%d%d", &n , &m ) == 2 && ( m + n ) ) { for ( int i = 0; i < n; ++i ) { scanf ( "%d%d", &dn[i].x, &dn[i].y ); nxt[i].clear(); } for ( int i = 0; i < m; ++i ) { scanf ( "%d%d", &dm[i].x, &dm[i].y ); } for ( int i = 0; i < n; ++i ) { for ( int j = 0; j < m; ++j ) { if ( test ( i, j ) ) { nxt[i].push_back ( j ); } } } memset ( fa, -1, sizeof fa ); int cnt = 0; for ( int i = 0; i < n; ++i ) { memset ( vis, 0, sizeof vis ); if ( fnd ( i ) ) { cnt++; } } printf ( "%d\n", n + m - cnt ); } return 0; }
hdu 1150 Machine Schedule
最小点覆盖#include <stdio.h> #include <vector> #include <string.h> #include <math.h> using namespace std; #define MAXN 1005 int fa[MAXN], vis[MAXN]; struct _node { int x, y; } dm[MAXN], dn[MAXN]; vector<int> nxt[MAXN]; int fnd ( int u ) { for ( unsigned int i = 0; i < nxt[u].size(); ++i ) { int v = nxt[u][i]; if ( vis[v] ) { continue; } vis[v] = 1; if ( fa[v] == -1 || fnd ( fa[v] ) ) { fa[v] = u; return 1; } } return 0; } int main() { #ifdef __GNUC__ freopen ( "in.txt", "r", stdin ); //freopen ( "out.txt", "w", stdout ); #endif // __GNUC__ int n, m, k; while ( scanf ( "%d", &n ) && n ) { scanf ( "%d%d", &m, &k ); for ( int i = 0; i < n; ++i ) { nxt[i].clear(); } for ( int i = 0, j; i < k; ++i ) { int u, v; scanf ( "%d%d%d", &j, &u, &v ); if ( u && v) nxt[u].push_back ( v ); } memset ( fa, -1, sizeof fa ); int cnt = 0; for ( int i = 1; i < n; ++i ) { memset ( vis, 0, sizeof vis ); if ( fnd ( i ) ) { cnt++; } } printf ( "%d\n", cnt ); } return 0; }