加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

BZOJ 1562 浅谈匈牙利算法性质挖掘以【变换序列】即最小字典序构

发布时间:2020-12-14 04:59:49 所属栏目:大数据 来源:网络整理
导读:世界真的很大 匈牙利算法并不是一个有许多性质可以挖掘或者拓展的算法 但是对于其思路还是必须要熟悉才行。 邻接表的具体构建方式已经忘得差不多了,只是背的到 算是都复习了一遍 认真想起来其实也不是很难 看题先: description: input: output : 要求选

这里写图片描述


世界真的很大
匈牙利算法并不是一个有许多性质可以挖掘或者拓展的算法
但是对于其思路还是必须要熟悉才行。
邻接表的具体构建方式已经忘得差不多了,只是背的到
算是都复习了一遍
认真想起来其实也不是很难

看题先:

description:

这里写图片描述

input:

这里写图片描述

output :

这里写图片描述

要求选一种满足题意的“置换”,使得字典序最小
不懂置换是什么的话就看这里:传送门
所谓满足条件,就是说原先序列的一个点最多有两个可以去的地方
合理安排每个点去哪个点,看能不能使得所有点都有一个去处
如果方案有多种的话,就输出字典序最小的那一种

能不能使每一个点都有一个去处,翻译一下就是:
求一种方案使尽量多的点有去处且不重叠,然后看点数到不到n
二分图最大匹配,看匹配数有没有n。
到此,判断有没有一种合法方案就结束了,问题在于输出字典序最小的方案。

思路能一下想到的有两个
一是再找找一种方法去求这种最小的字典序的方案
感觉~~有点难

二呢,考虑到,求出最大匹配之后,match数组保存的匹配边已经是一种方案了,只不过可能不是最小而已,有没有什么办法暗箱操作一下匈牙利算法的过程,使得求出的正好是最小字典序呢?

怎么想都是第二种看起来实现难度低一点

复习一下匈牙利算法的实现流程:传送门
即,在每一次新点匹配的时候,如果能匹配,那自然是直接匹配,反之就会去看前面的点能不能让出这一个空位
即是说,以后匹配的点为优先。
那我们越想让哪个点取得最小值,越应该让其匹配顺序靠后,因为这样他收到其他店的干扰就越小。
由于是字典序最小,我们肯定是让编号小的取到较靠前的位置。
为了防止这些位置被其他点所占据,我们肯定是让编号小的点后匹配
那么对于一个点,我们肯定优先想让其匹配较靠前的点,这个怎么处理?
自然是在加边的时候判一下就好

考虑邻接表,有着“后加的边先跑”的原则。所以我们只需要在加边的时候,先加大的,再加小的,就行了

满足这两个约束条件后,跑出来的匹配是不是字典序最小的匹配呢?
答案是肯定的

若问为何?
他A了不是吗233

完整代码:

#include<stdio.h>

struct edge
{
    int v,last;
}ed[4000010];

int n,ans=0,tot=0,num=0;
int head[200010],book[200010],match[200010];

void add(int u,int v)
{
    num++;
    ed[num].v=v;
    ed[num].last=head[u];
    head[u]=num;
}

int dfs(int u)
{
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(book[v]!=tot)
        {
            book[v]=tot;
            if(!match[v] || dfs(match[v]))
            {
                match[u]=v,match[v]=u;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int d;
        scanf("%d",&d);
        int a=(i+d)%n+n,b=(i-d+n)%n+n;
        if(a>b) add(i,a),add(i,b);
        else add(i,b),a);
    }
    for(int i=n-1;i>=0;i--)
    {
        tot++;
        if(!match[i]) ans+=dfs(i);
    }
    if(ans<n) printf("No Answer");
    else
    {
        for(int i=0;i<n;i++)
        {
            printf("%d",match[i]-n);
            if(i!=n-1) printf(" ");
        }
    }
    return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/

嗯,就是这样

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读