带花树模板

#include<bits/stdc++.h>
using namespace std;
const int N=1001;
struct ty
{
    int next, t;
}edge[N*N];
int fa[N],col[N],match[N],vis[N],last[N],n,m,M,head[N],x[N],y[N],L;
//next[i]  存的是i在bfs中沿着非匹配边走到的上一个点
int tmp = 0;
queue<int> q;
void addedge(int x, int y)
{
    edge[++M]=(ty){head[x], y};
    head[x] = M;
}
int findfa(int x)
{
    return fa[x] == x ? x : fa[x] = findfa(fa[x]);
}
int lca(int x, int y) //求环顶
{
    tmp++; //为了不清vis数组,让每次进入函数的时候给vis赋的值都不一样就可以了
    while(1)
    {
        if(x != 0)
        {
            x = findfa(x); //先去x的环顶
            if(vis[x] == tmp) return x;//x走过了,说明已经是环顶了,返回
            vis[x] = tmp; //标记走过
            if(match[x]) x = last[match[x]]; //我往上跳一条匹配边和非匹配边(BFS一层是走了一条匹配边和一条非匹配边)
            else x = 0;
        }
        swap(x, y); //交换xy
    }
}
void flower(int a,int r) //缩环(的一半)
{
    while(a != r)
    {
        int b = match[a], c = last[b]; //a是黑点所以先跳匹配边然后再跳非匹配边
        if(findfa(c) != r) last[c] = b; //因为奇环里到底怎么匹配还不知道,干脆把原来的匹配边也记录一组非匹配边(这样之后就能利用last做任意相邻两个的匹配了)
        if(col[b] == 2) q.push(b), col[b] = 1;
        if(col[c] == 2) q.push(c), col[c] = 1;  //环上的白点要变成黑点(之前本来是交错的黑白,但是直接一个判断就不用关心哪个位置黑哪个位置白了)
        fa[findfa(a)] = findfa(b);
        fa[findfa(b)] = findfa(c);  //并查集维护父亲
        a = c;  //往上跳
    }
}
int work(int s)
{
    for(int i = 1; i <= n; i++)
        last[i] = col[i] = vis[i] = 0, fa[i] = i;  //清数组
    while(!q.empty()) q.pop();
    col[s] = 1;//给起点标成黑色
    q.push(s);
    while(!q.empty())   //广搜
    {
        int x = q.front();
        q.pop();
        for(int i = head[x]; i > 0; i = edge[i].next)
        {
            int y = edge[i].t;
            if(match[x] == y) continue;  //走的匹配边(走回去了)
            if(findfa(x) == findfa(y)) continue; //两个点在同一个已经缩过的奇环里
            if(col[y] == 2) continue; //偶环
            if(col[y] == 1)  //黑点——奇环
            {
                int r = lca(x, y);  //r是环顶
                if(findfa(x) != r) last[x]=y;
                if(findfa(y) != r) last[y]=x;  //xy都是靠非匹配边接在一起的
                flower(x, r);
                flower(y, r);  //缩花,每次缩掉花的一半
            }
            else if(!match[y]) //else表示col等于0——在这次增广中y没访问过;match为0,这个点是个为匹配的点——增广路已经求到了
            {
                last[y] = x;  //y通过非匹配边和x连到一起
                for(int u = y;u != 0;)  //顺着交错路走回去
                {
                    int v = last[u];  //last是他通过非匹配边连的上一个点
                    int w = match[v]; //去v原来匹配的点
                    match[v] = u;
                    match[u] = v;     //匹配边和非匹配边交换——所以uv成为新的一对
                    u = w;    //再从被“抛弃”的那个点开始往前走直到把这个增广路的修改修改完
                    //这里之所以没有改last的值是因为用过了就没用了,后面会退出work函数,再次进入就清空了
                }
                return 1;  //本次增广已经找到增广路了

            }
            else //col等于0——在这次增广中y没访问过,且y原来有匹配
            {
                last[y] = x; //通过未匹配边的y的前一个点为x
                col[y] = 2; //y自己是白点
                col[match[y]] = 1; //y通过匹配边连的前一个点是黑点
                q.push(match[y]);  //这个黑点入队

            }
        }
    }
    return 0;
}
void init(){
    memset(match, 0, sizeof(match));
    memset(head, 0, sizeof(head));
    M = 0;
    for(int i = 1; i <= n; i++)
        scanf("%d%d", &x[i], &y[i]);
    scanf("%d", &L);
    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) {addedge(i, j); addedge(j, i);}
    }
    for(int i = 1; i <= n; i++)
    {
        if(!match[i])
        {
            if(!work(i))
            {
                cout<<"NO\n";
                return;
            }
        }
    }
    cout<<"YES\n";
}
int main()
{
    while(scanf("%d", &n) != EOF)
    init();
    return 0;
}

全部评论

相关推荐

03-15 14:55
已编辑
门头沟学院 golang
bg:双非学院本&nbsp;ACM银&nbsp;go选手timeline:3.1号开始暑期投递3.7号第二家公司离职顽岩科技&nbsp;ai服务中台方向&nbsp;笔试➕两轮面试,二面挂(钱真的好多😭)厦门纳克希科技&nbsp;搞AI的,一面OC猎豹移动&nbsp;搞AIGC方向&nbsp;一面OC北京七牛云&nbsp;搞AI接口方向&nbsp;一面OC上海古德猫宁&nbsp;搞AIGC方向&nbsp;二面OC上海简文&nbsp;面试撞了直接拒深圳图灵&nbsp;搞AIGC方向一面后无消息懒得问了,面试官当场反馈不错其他小厂没记,通过率80%,小厂杀手😂北京字节&nbsp;具体业务不方便透露也是AIGC后端方向2.28约面&nbsp;(不知道怎么捞的我,我也没在别的地方投过字节简历哇)3.6一面&nbsp;一小时&nbsp;半小时拷打简历(主要是AIGC部分)剩余半小时两个看代码猜结果(经典go问题)➕合并二叉树(秒a,但是造case造了10分钟哈哈)一天后约二面3.12&nbsp;二面,让我挑简历上两个亮点说,主要说的docker容器生命周期管理和raft协议使用二分法优化新任leader上任后与follower同步时间。跟面试官有共鸣,面试官还问我docker底层cpu隔离原理和是否知道虚拟显存。之后一道easy算法,(o1空间解决&nbsp;给定字符串含有{和}是否合法)秒a,之后进阶版如何用10台机加快构建,想五分钟后a出来。面试官以为45分钟面试时间,留了18分钟让我跟他随便聊,后面考了linux&nbsp;top和free的部分数据说什么意思(专业对口了只能说,但是当时没答很好)。因为当时手里有7牛云offer,跟面试官说能否快点面试,马上另外一家时间到了。10分钟后约hr面3.13,上午hr面,下午走完流程offer到手3.14腾讯技术运营约面,想直接拒😂感受:&nbsp;因为有AIGC经验所以特别受AI初创公司青睐,AIGC后端感觉竞争很小(指今年),全是简历拷打,基本没有人问我八股(八股吟唱被打断.jpeg),学的东西比较广的同时也能纵向深挖学习,也运气比较好了哈哈可能出于性格原因,没有走主流Java路线,也没有去主动跟着课写项目,项目都是自己研究和写的哈哈
烤点老白薯:你根本不是典型学院本的那种人,贵了你这能力
查看7道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务