• P1963 [NOI2009]变换序列


    https://www.luogu.org/problemnew/show/P1963

     

    题目描述

    对于 NN 个整数 0, 1, cdots, N-10,1,,N1 ,一个变换序列 TT 可以将 ii 变成 T_iTi ,其中 T_i in { 0,1,cdots, N-1}Ti{0,1,,N1} 且 igcup_{i=0}^{N-1} {T_i} = {0,1,cdots , N-1}i=0N1{Ti}={0,1,,N1} 。 , forall x,y in {0,1,cdots , N-1}x,y{0,1,,N1} ,定义x和y之间的距离 D(x,y)=min{|x-y|,N-|x-y|}D(x,y)=min{xy,Nxy} 。给定每个 ii 和 T_iTi 之间的距离 D(i,T_i)D(i,Ti) ,你需要求出一个满足要求的变换序列T。如果有多个满足条件的序列,输出其中字典序最小的一个。

    说明:对于两个变换序列 SS 和 TT ,如果存在 p<Np<N ,满足对于 i=0,1,cdots p-1i=0,1,p1 , S_i=T_iSi=Ti 且 S_p<T_pSp<Tp ,我们称 SS 比 TT 字典序小。

    输入输出格式

    输入格式:

    第一行包含一个整数 NN ,表示序列的长度。接下来的一行包含 NN 个整数 D_iDi ,其中 D_iDi 表示 ii 和 T_iTi 之间的距离。

    输出格式:

    如果至少存在一个满足要求的变换序列 TT ,则输出文件中包含一行 NN 个整数,表示你计算得到的字典序最小的 TT ;否则输出No Answer(不含引号)。注意:输出文件中相邻两个数之间用一个空格分开,行末不包含多余空格。

    输入输出样例

    输入样例#1: 复制
    5
    1 1 2 2 1
    
    输出样例#1: 复制
    1 2 4 0 3

    说明

    对于30%的数据,满足:N<=50;

    对于60%的数据,满足:N<=500;

    对于100%的数据,满足:N<=10000。

    /*
    题里面对D(x,y)的定义那一长句,一开始没看明白,但实际会发现是一个环,而对于每一个点u,符合给定距离的点都有且只有2个(v1&&v2),连u->v1和u->v2。
    连边的时候注意先连终点序号大的,这样才能保证遍历时从小到大。
    为什么要做这个操作呢?因为要求输出字典序最小的解,就必须保证较小的点优先匹配较小的点。
    匈牙利算法的过程,总是通过调整先前匹配的点,而使当前点尽量不动。
    所以,匈牙利算法倒序跑,增广时优先选小的点,这样就能够保证「越小的点越能匹配较小的点」,从而实现字典序最小化。(贪心思想)
    最终输出X部每个点的匹配点即可。
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    using namespace std;
    
    const int N=20010;
    
    bool vis[N];
    int n,ans;
    int head[N],num_edge;
    int match[N];
    struct edge
    {
        int v,nxt;
    }edge[N];
    
    int solve(int x)
    {
        if(x<0)
            x+=n;
        if(x>=n)
            x-=n;
        return x+n;
    }
    
    void add_edge(int u,int x)
    {
        int v1=solve(u+x),v2=solve(u-x);
        if(v1<v2)
            swap(v1,v2);
        edge[++num_edge].v=v1;
        edge[num_edge].nxt=head[u];
        edge[++num_edge].v=v2;
        edge[num_edge].nxt=num_edge-1;
        head[u]=num_edge;
    }
    
    bool dfs(int u)
    {
        for(int i=head[u],v;i;i=edge[i].nxt)
        {
            if(!vis[v=edge[i].v])
            {
                vis[v]=1;
                if(!match[v]||dfs(match[v]))
                {
                    match[u]=v,match[v]=u;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    bool Hungary()
    {
        for(int i=n-1;i>=0;--i)
            if(!match[i])
            {
                memset(vis,0,sizeof vis);
                ans+=dfs(i);
            }
        return n==ans;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=0,x;i<n;++i)
        {
            scanf("%d",&x);
            add_edge(i,x);
        }
        if(Hungary())
            for(int i=0;i<n;++i)
                printf("%d ",match[i]-n);
        else
            printf("No Answer");
        return 0;
    }
  • 相关阅读:
    聊聊和关系型数据库相关的一些概念
    Spring-MongoDB 关键类的源码分析
    Studio 3T 如何使用 Query Builder 查询数据
    MySQL error : Deadlock found when trying to get lock; try restarting transaction
    The java.util.concurrent Synchronizer Framework笔记
    JDK 8
    MongoDB Data Model 浅谈
    Java 泛型分析
    DCL(双检锁)的失效:现实与初衷的背离
    vue之虚拟dom
  • 原文地址:https://www.cnblogs.com/lovewhy/p/9029375.html
Copyright © 2020-2023  润新知