zoj3316【一般图最大匹配 带花树开花】

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3726

算法见:http://fanhq666.blog.163.com/blog/static/8194342620120304463580/

题意:棋盘上有n个点,现在两个人轮流在移除一个子,每次移除的子距离上次移除的子曼哈顿距离小于L。最后不能移除的人输。

分析:将距离小于L的点连边。如果一个连通块不是是完备匹配,先手一定可以让自己走到一个没有匹配的点上,然后后手就不能移除子了,如果后手可以移除子,那么就有了新的匹配,现在就是一个完备匹配了。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 400
#define Mm 200005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
    int v,next;
}e[Mm];
struct point {
    int x,y;
}p[Mn];
int dis(point a,point b) {
   return abs(a.x-b.x)+abs(a.y-b.y);
}
int tot,head[Mn];
void addedge(int u,int v) {
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
int pre[Mn];
int findpre(int x) {
    return x==pre[x]?pre[x]:pre[x]=findpre(pre[pre[x]]);
}
void ol(int a,int b) {
    a=findpre(a);
    b=findpre(b);
    if(a!=b) pre[a]=b;
}
int n,lk[Mn],vis[Mn],mark[Mn],match[Mn],ne[Mn];
int lca(int x,int y) {
    static int t=0;t++;
    while(1) {
        if(x!=-1) {
            x=findpre(x);
            if(vis[x]==t) return x;
            vis[x]=t;
            if(match[x]!=-1) x=ne[match[x]];
            else x=-1;
        }
        swap(x,y);
    }

}
queue<int> q;
void group(int a,int p) {
    while(a!=p) {
        int b=match[a],c=ne[b];
        if(findpre(c)!=p) ne[c]=b;
        if(mark[b]==2) mark[b]=1,q.push(b);
        if(mark[c]==2) mark[c]=1,q.push(c);
        ol(a,b),ol(b,c);
        a=c;
    }
}
void aug(int s) {
    for(int i=0;i<=n;i++) {
        ne[i]=-1;
        pre[i]=i;
        mark[i]=0;
        vis[i]=-1;
    }
    mark[s]=1;
    while(!q.empty()) q.pop();
    q.push(s);
    while((!q.empty())&&match[s]==-1) {
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].v;
            if(match[u]==v||findpre(u)==findpre(v)||mark[v]==2) continue;
            if(mark[v]==1) {
                int r=lca(u,v);
                if(findpre(u)!=r) ne[u]=v;
                if(findpre(v)!=r) ne[v]=u;
                group(u,r);
                group(v,r);
            } else if(match[v]==-1) {
                ne[v]=u;
                for(int x=v;~x;) {
                    int y=ne[x];
                    int mv=match[y];
                    match[x]=y,match[y]=x;
                    x=mv;
                }
                break;
            } else {
                ne[v]=u;
                q.push(match[v]);
                mark[match[v]]=1;
                mark[v]=2;
            }
        }
    }
}
void init() {
    tot=0;
    CLR(head,-1);
}
int main() {
    while(~scanf("%d",&n)) {
        int l;init();
        for(int i=1;i<=n;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        scanf("%d",&l);
        for(int i=1;i<n;i++) {
            for(int j=i+1;j<=n;j++) {
                if(dis(p[i],p[j])<=l) {
                    addedge(i,j);
                    addedge(j,i);
                }
            }
        }
        for(int i=1;i<=n;i++) match[i]=-1;
        for(int i=1;i<=n;i++) {
            if(match[i]==-1) aug(i);
        }
        int ans=0;
        for(int i=1;i<=n;i++) {
            if(match[i]!=-1) ans++;
        }
        if(ans==n) {
            printf("YES\n");
        } else printf("NO\n");
    }
    return 0;
}
时间: 2024-08-29 13:10:22

zoj3316【一般图最大匹配 带花树开花】的相关文章

poj 3020 一般图最大匹配 带花树开花算法

题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w <= 10 思路: 最小边覆盖=|V|-最大匹配 一般图最大匹配,带花树开花算法 /*poj 3020 一般图最大匹配 带花树开花算法 题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w &l

【UOJ 79】 一般图最大匹配 (?带花树开花)

从前一个和谐的班级,所有人都是搞OI的.有 n 个是男生,有 0 个是女生.男生编号分别为 1,-,n. 现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽.每个人至多属于一个小组. 有若干个这样的条件:第 v 个男生和第 u 个男生愿意组成小组. 请问这个班级里最多产生多少个小组? 输入格式 第一行两个正整数,n,m.保证 n≥2. 接下来 m 行,每行两个整数 v,u 表示第 v 个男生和第 u 个男生愿意组成小组.保证 1≤v,u≤n,保证 v≠u,保证同一个条

HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力

一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 如果C2+2==C1则这条边再某个最大匹配中 Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 649    Accepted Submission(s): 202

ZOJ 3316 Game 一般图最大匹配带花树

一般图最大匹配带花树: 建图后,计算最大匹配数. 如果有一个联通块不是完美匹配,先手就可以走那个没被匹配到的点,后手不论怎么走,都必然走到一个被匹配的点上,先手就可以顺着这个交错路走下去,最后一定是后手没有路可走,因为如果还有路可走,这一条交错路,就是一个增广路,必然有更大的匹配. Game Time Limit: 1 Second      Memory Limit: 32768 KB Fire and Lam are addicted to the game of Go recently.

一般图最大匹配带花树

参考博客:http://blog.sina.com.cn/s/blog_95ec9e7401018bga.html https://www.cnblogs.com/owenyu/p/6858508.html 用Dinic实现的二分图匹配的时间复杂度其实是O(M*N^0.5),这也许能够解释为什么一般网络流算法比Hungry要快了. 另外,带花树算法的正确性的证明比较困难:而其时间复杂度是可以做到O(M*N^0.5)的 简述一下“带花树”算法吧: 它的核心思想还是找增广路.假设已经匹配好了一堆点,

Work Scheduling URAL - 1099 一般图最大匹配带花树

#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <string> using namespace std; const int MAXN = 250; int N; //点的个数,点的编号从1到N bool Graph[MAXN][MAXN]; int Match[MAXN]; bool InQueue[MAXN],I

kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图. 1.一个二分图中的最大匹配数等于这个图中的最小点覆盖数 König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数.如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选

URAL 1099. Work Scheduling 一般图匹配带花树

一般图匹配带花树模版题: 将奇环缩成圈(Blossom),然后找增广路..... 1099. Work Scheduling Time limit: 0.5 second Memory limit: 64 MB There is certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to sche

【ZOJ3316】Game(带花树)

[ZOJ3316]Game(带花树) 题面 Vjudge 翻译: 给定棋盘上\(n\)个旗子 一开始先手可以随便拿, 然后每次都不能取离上次的曼哈顿距离超过\(L\)的旗子 谁不能动谁输. 问后手能否赢? 题解 假的博弈论 对于所有曼哈顿距离小于等于\(L\)的点连边 检查是否存在完美匹配 如果存在完美匹配,每次先手选择一个点,后手只需要选择对应的点即可. 否则一定存在一个无法匹配的点,与它曼哈顿距离小于等于\(L\)的个数一定是偶数个(如果是奇数个就会与它匹配) 那么这个联通块的大小是奇数个,