首先谈谈对最小路径覆盖核心函数的理解:每次从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 4606 Occupy Cities
图论(线段交叉),最小路径覆盖。。。。
貌似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;
}
hdu 4619 Warm up 2
匈牙利算法,但核心与最小路径覆盖一致,都是逐渐扩增
#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; }