【ZOJ3316】Game(带花树)

【ZOJ3316】Game(带花树)

题面

Vjudge
翻译:
给定棋盘上\(n\)个旗子
一开始先手可以随便拿,
然后每次都不能取离上次的曼哈顿距离超过\(L\)的旗子
谁不能动谁输。
问后手能否赢?

题解

假的博弈论

对于所有曼哈顿距离小于等于\(L\)的点连边
检查是否存在完美匹配
如果存在完美匹配,每次先手选择一个点,后手只需要选择对应的点即可。
否则一定存在一个无法匹配的点,与它曼哈顿距离小于等于\(L\)的个数一定是偶数个(如果是奇数个就会与它匹配)
那么这个联通块的大小是奇数个,后手必败。(假的证明)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 362
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Line{int v,next;}e[MAX*MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int dfn[MAX],tim;
int f[MAX],n;
int pre[MAX],vis[MAX],match[MAX];
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
int lca(int u,int v)
{
    ++tim;u=getf(u),v=getf(v);
    while(dfn[u]!=tim)
    {
        dfn[u]=tim;
        u=getf(pre[match[u]]);
        if(v)swap(u,v);
    }
    return u;
}
queue<int> Q;
void blossom(int x,int y,int w)
{
    while(getf(x)!=w)
    {
        pre[x]=y;y=match[x];
        if(vis[y]==2)vis[y]=1,Q.push(y);
        if(f[x]==x)f[x]=w;
        if(f[y]==y)f[y]=w;
        x=pre[y];
    }
}
bool Aug(int S)
{
    for(int i=1;i<=n;++i)f[i]=i,vis[i]=pre[i]=0;
    while(!Q.empty())Q.pop();Q.push(S);vis[S]=1;
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int i=h[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if(getf(u)==getf(v)||vis[v]==2)continue;
            if(!vis[v])
            {
                vis[v]=2;pre[v]=u;
                if(!match[v])
                {
                    for(int x=v,lst;x;x=lst)
                        lst=match[pre[x]],match[x]=pre[x],match[pre[x]]=x;
                    return true;
                }
                vis[match[v]]=1;Q.push(match[v]);
            }
            else
            {
                int w=lca(u,v);
                blossom(u,v,w);blossom(v,u,w);
            }
        }
    }
    return false;
}
void init()
{
    memset(h,0,sizeof(h));cnt=1;
    memset(match,0,sizeof(match));
}
int X[MAX],Y[MAX],L;
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;++i)X[i]=read(),Y[i]=read();
        L=read();int ans=0;
        if(n&1){puts("NO");continue;}
        for(int i=1;i<=n;++i)
            for(int j=i+1;j<=n;++j)
                if(abs(X[i]-X[j])+abs(Y[i]-Y[j])<=L)
                    Add(i,j),Add(j,i);
        for(int i=1;i<=n;++i)if(!match[i])ans+=Aug(i);
        (ans==n/2)?puts("YES"):puts("NO");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8719571.html

时间: 2024-08-02 23:24:55

【ZOJ3316】Game(带花树)的相关文章

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

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

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

HDU 4687 Boke and Tsukkomi(一般图匹配|带花树)

比赛的时候刚开始看这题还以为是二分图匹配,后来才发现根本不是,因为该题存在长度为奇数的圈 .  比如1->2,2->3,3->1 . 所以该题要用一般图匹配,即带花树算法 . 比赛时抄的模板有地方抄错了,上述样例出现了死循环 .   赛后补题的时候用map去重却得不到正确答案,不知为何,暂放 ,下面给出一种正确解法. 细节参见代码: #include<cstdio> #include<cstring> #include<iostream> #inclu

带花树算法

先贴上大神博客,再说说自己的理解 http://blog.csdn.net/xuezhongfenfei/article/details/10148445 一般图匹配 嗯 怎么办 我们回想解决二分图匹配的算法 --匈牙利算法 匈牙利算法, "如果一个男生可以勾搭上一个妹子, 而且使得之前的所有男生都还有妹子,那这个妹子就是他的了!" 怎么办,我们需要带花树算法. 我们先钦定一个匹配两个点哪个是男的哪个是女的, 如果当前一个男点想勾搭一个女点,说明找到一个偶环,无视他(好可怜) 如果一个

带花树

带花树模板 1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define N 605 6 #define M 200010 7 using namespace std; 8 int n,m,tot,head[N],match[N],fa[N],flower[N]; 9 bool inflower[N],vis[N]; 10 struct edg

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

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

带花树学习

被大神hzm鄙视了一番,我便觉得这个带花树非学不可啦!!话不多说,下面就是我的学习随笔! 带花树算法就是用来解决一般图的匹配问题.一般图匹配自然是比二分图匹配高级的东西!所以立马屁颠屁颠地去复习了匈牙利算法.这两个算法的核心思想都是"增广"!既然这样,我们就通过对匈牙利算法增广概念的复习来引入带花树算法的增广从而理解带花树算法吧!!_(:зゝ∠)_ 匈牙利算法的增广路 咳咳,我们来复习一下二分图匹配的问题吧!已知集合S和集合T以及若干S集合中的元素到T集合中的元素的二元关系(s,t).

HDU 4687 Boke and Tsukkomi 一般图匹配,带花树,思路,输出注意空行 难度:4

http://acm.hdu.edu.cn/showproblem.php?pid=4687 此题求哪些边在任何一般图极大匹配中都无用,对于任意一条边i,设i的两个端点分别为si,ti, 则任意一个极大匹配中都必然有si或ti至少一个点被匹配,当在图中去掉si,ti两个点时,匹配数会损失一个或两个. 如果损失两个,就说明在极大匹配中这两个点分别连接不同的边,于是边i是无用的 所以总体思路:一般图匹配求出最大匹配数cnt0,分别试着去掉每条边的端点,再次匹配,匹配数如果小于cnt0-1,则这条边无

任意图匹配 带花树模版(转)

匹配就是一个图中一堆没有端点的边的集合,求最大匹配就是求这个边集最大有多少条边. 无论是任意图还是二分图,都有以下定理: 当前匹配是最大匹配当且仅当不存在增广路. 增广路的定义就是,一条包含奇数条边的路径,最前和最后的两条边都是非匹配边,且对于路径非两端的点,都连接着一条匹配边和非匹配边. 求图的匹配的算法就是不断地找增广路,把增广路上的匹配边变成非匹配边,非匹配边变成匹配边. 对于二分图来说,只要从一个没有被匹配到的点开始bfs(dfs)一下就能找到增广路(如果确实有增广路). 但是对于任意图