hdu 6808 Go Running( 最小点覆盖+网络流 )

hdu 6808 Go Running( 最小点覆盖+网络流 )

hdu6808

必须知道的定理:

最小点覆盖:在二分图中,求最少的点集,使得每一条边至少都有端点在这个点集中。

最小点覆盖 = 最大匹配 (条件:在二分图中)

题意:在一条无限长x轴上,上面有若干人在以1m/s的速度向右或向左匀速运动,相机抓拍了n张照片,包含两个属性x和t,表示在t时刻在x点有一个人。问在整个轴上最少有几个人。比如x=1,t=2和x=3,t=4可以是一个人。

思路:画一个x-t图像可以看出来,每个点都可以延展到y轴上表示相应的两个点。所以对于给的某个点,要么是从左上方延展过来的,要么是从左下方延展过来的。到底该怎么选才能保证人数最少?这就用到了最小点覆盖,比如说x=1,t=2,可以是x0=3或者是x0=-1来的,那么我们就构建二分图,让3连接-1,最小点覆盖一定会最优的选择这个边上的至少一个点。不会匈牙利用网络流写的。

hdu 6808 Go Running( 最小点覆盖+网络流 )_第1张图片

 

代码:

#include 

using namespace std;

struct node {
    int to,f,nxt;
};
const int maxn = 2e6+10;
node e[maxn];
int n,m,s,t;
int head[maxn];
int cur[maxn];
int dep[maxn];
int cnt;

void addage( int u, int v, int f )
{
    e[cnt].to = v;
    e[cnt].f = f;
    e[cnt].nxt = head[u];
    head[u] = cnt++;
}

int bfs(int node)
{
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(cur)); // 复制head数组
    dep[node] = 1;
    queue  Q;
    Q.push(node);
    while ( !Q.empty() ) {
        int x = Q.front();Q.pop();
        for ( int i=head[x]; i!=-1; i=e[i].nxt ) {
            int y = e[i].to,f = e[i].f;
            if ( !dep[y] && f ) {
                dep[y] = dep[x] + 1;
                Q.push(y);
            }
        }
    }
    return dep[t]; // return dep[t] , 如果是0那么说明没有增广路了,退出while
}

int dfs( int x, int flow ) // dfs找增广路
{
    if ( x==t ) {
        return flow;
    }
    int sum = 0;
    for ( int i=cur[x]; i!=-1; i=e[i].nxt ) {
        cur[x] = i;
        int y = e[i].to, f = e[i].f;
        if ( f && dep[y]==dep[x]+1 ) {
            int t = dfs(y,min(flow-sum,f)); // 优化1
            sum += t;
            e[i].f -= t;
            e[i^1].f += t;
            if ( sum==flow ) break; // 优化1
        }
    }
    if ( sum==0 ) { // 如果sum==0,那么这个点之前没有增广路,深度清零
        dep[x] = 0;
    }
    return sum;
}

int x[maxn],y[maxn];
int a[maxn],b[maxn];

int main()
{
    int T;cin>>T;
    while ( T-- ) {
        cin>>n;
        memset(head,-1,sizeof(head));cnt = 0;
        for ( int i=0; i

 

 

你可能感兴趣的:(2020多校赛)