最小路径覆盖合集

首先谈谈对最小路径覆盖核心函数的理解:每次从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;
}


你可能感兴趣的:(最小路径覆盖合集)