HDU 6808 Go Running(二分图最小顶点覆盖)

题意:给出N个元组(x, y)问最多需要多少个初始状态才能转移到这样,一个元组(x,y)可以一直向右转移(x+1, y+1)...(x+i, y+i)或者一直向左转移(x+i, y-i)。n<1e5, x,y<1e9

题解:选择最少的直线,能够包括所有给定的点(x,y),把斜率1和-1的直线分别作为二分图u,v部分,当前有(x,y)即对两条直线加边,求的即是二分图的最小顶点覆盖。

   二分图最小顶点覆盖定义:假如选了一个点就相当于覆盖了以它为端点的所有边。最小顶点覆盖就是选择最少的点来覆盖所有的边。

HK算法:

#include <bits/stdc++.h>
#define IO_read ios::sync_with_stdio(false);cin.tie(0)
#define fre freopen("C:\\in.txt", "r", stdin)
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
#define inf 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
using namespace std;
typedef long long ll;
template <class T>
void read(T &x)
{
    char c; bool op=0;
    while(c=getchar(), c<'0'||c>'9') if(c=='-') op=1;
    x=c-'0';
    while(c=getchar(), c>='0'&&c<='9') x=x*10+c-'0';
    if(op) x=-x;
}
template <class T>
void write(T x)
{
    if(x<0) putchar('-'), x=-x;
    if(x>=10) write(x/10);
    putchar('0'+x%10);
}

const int maxn=1e5+5;
unordered_map<int, int> line1, line2;
int T, n;

/* //hungry算法复杂度:VE TEL
vector<int> g[maxn];
int un, vn;
int linker[maxn], used[maxn];

bool dfs(int u)
{
    for(auto &v: g[u]){
        if(!used[v]){
            used[v]=true;
            if(linker[v]==-1 || dfs(linker[v])){
                linker[v]=u;
                return true;
            }
        }
    }
    return false;
}

int hungry()
{
    int res=0;
    memset(linker, -1, sizeof(linker));
    for(int u=1; u<=un; u++){
        memset(used, 0, sizeof(used));
        if(dfs(u)) res++;
    }
    return res;
}
*/

// hk算法时间复杂度sqrt(V)*E
vector<int> g[maxn];
int un, vn;
int linker[maxn], used[maxn];
int mx[maxn], my[maxn], dx[maxn], dy[maxn], dis;

bool search_path()
{
    queue<int> que;
    dis=inf;
    memset(dx, -1, sizeof(dx));
    memset(dy, -1, sizeof(dy));
    for(int u=1; u<=un; u++){
        if(mx[u]==-1) que.push(u), dx[u]=0;
    }
    while(!que.empty())
    {
        int u=que.front(); que.pop();
        if(dx[u]>dis) break;
        for(auto &v: g[u]){
            if(dy[v]==-1){
                dy[v]=dx[u]+1;
                if(my[v]==-1) dis=dy[v];
                else dx[my[v]]=dy[v]+1, que.push(my[v]);
            }
        }
    }
    return dis!=inf;
}

bool dfs(int u)
{
    for(auto &v: g[u])
    {
        if(!used[v] && dy[v]==dx[u]+1){
            used[v]=true;
            if(my[v]!=-1 && dy[v]==dis) continue;
            if(my[v]==-1 || dfs(my[v])){
                my[v]=u, mx[u]=v;
                return true;
            }
        }
    }
    return false;
}

int hopcroft_karp()
{
    int res=0;
    memset(mx, -1, sizeof(mx));
    memset(my, -1, sizeof(my));
    while(search_path()){
        memset(used, 0, sizeof(used));
        for(int u=1; u<=un; u++)
            if(mx[u]==-1 && dfs(u)) res++;
    }
    return res;
}


int main()
{
    read(T);
    while(T--)
    {
        read(n);
        un=vn=0;
        _rep(i, 1, n) g[i].clear();
        line1.clear(), line2.clear();
        int x, y;
        _rep(i, 1, n){
            read(x), read(y);
            int k1=y-x, k2=y+x;
            if(!line1[k1]) line1[k1]=++un;
            if(!line2[k2]) line2[k2]=++vn;
            g[line1[k1]].push_back(line2[k2]);
        }
        //printf("%d\n", hungry());
        printf("%d\n", hopcroft_karp());
    }
    return 0;
}

 

posted @ 2020-08-01 22:15  N_Yokel  阅读(198)  评论(0编辑  收藏  举报