• 【NOI2009】Bzoj1562&Codevs1843 变换序列


    Position:


    List

    Description

      bzoj1562

    Input

    输入文件 transform.in 的第一行包含一个整数 N,表示序列的长度。接下来的
    一行包含 N 个整数 D i ,其中 D i 表示 i 和 T i 之间的距离。

    Output

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

    Sample Input

     5
    1 1 2 2 1

    Sample Output

    1 2 4 0 3

    HINT

    30%的数据中 N≤50;
    60%的数据中 N≤500;
    100%的数据中 N≤10000。

    Solution

    观察题中给的式子,发现每个位置可以填两个数,但只能填一个数,求是否每个位置可以填上一个不重复的0~n-1的数,并保证字典序最小,也就是填在前面的数要尽量小。
    最小字典序的匈牙利,贪心发现可以倒着来跑匈牙利,保证对于当前位置的数尽量小,替换掉的是后面的数,后面的数也保证了尽量小。而正着来后面的数可能会替换掉之前的数,不满足字典序最小。

    官方题解%莫队

    Transform解题报告
    湖南省长郡中学 莫涛
    【题目大意】
    给定n和{Ti},求一个字典序最小的0..n-1的排列{Pi},使{Pi}满足{,或指出无解。
    n<=10000。
    【解法分析】
     不难看出,所给限制即i与Pi的环上距离为Ti,故对于任意i,至多存在两个Pi(从i顺时针或逆时针移动Ti距离)满足限制。
     构建二分图模型,以0,1..n-1为X节点,0,1..n-1为Y节点,若Pi=j满足限制则由X的i节点向Y的j节点连一条边,则问题转化为判断是否存在完备匹配,若存在则求出字典序最小的匹配方案。
    【算法一】
    首先使用匈牙利算法求解,若不存在完备匹配则返回无解,否则按如下流程调整使得求得字典序最小解:

    for do
    ·if i与ai,bi(ai>bi)有边且i与ai匹配 then
    ·删去匹配边(i,ai)并暂时禁用该边
    ·令j为原来与bi匹配的点
    ·将i与bi匹配
    ·if 从j出发可以找到增广路 then
    ·保留该次增广,并在以后的增广中禁止改变匹配边(i,bi)
    ·else 还原上述改动

     该算法的核心思想即利用字典序比较的特性,从前往后尝试改小每一位,若更改后剩余部分存在可行解则永久保留该次更改,否则撤销。
    由于每个点至多有两条出边,故只在取了匹配了编号较大的点时尝试匹配编号较小的点,而剩下部分有可行解的条件为存在完备匹配,若直接用匈牙利算法求解则时间复杂度为O(n^3),但我们知道:
    对于任意残量网络,使用增广路算法均可求得最大流(最大匹配)。
    而对于任意k(k>i),k均已匹配,故只需从i出发寻找增广路即可,这样时间复杂度就是O(n^2)了,可以通过测试数据。
    【算法二】
    考虑到该图非常特殊(X节点出度至多为2),可以从图论的角度求解。
    首先,如果存在度为1的点,那么可以直接确定匹配,故可以使用队列持续删去度为1的点及其确定的匹配点及于它们相关的边,直到不存在度为1的点。
    然后,如果此时存在度为0的解,那么可以直接返回无解。
    最后,由于所有的X节点度大于1且不大于2,故度均为2;而所有Y节点度大于1且∑d(X)=∑d(Y),故所有Y节点度均为2。
    一个所有点度均为2的图必然是若干不相交的环。而一个环中只存在两种匹配方案,直接选择较小者即可。
    该算法时间复杂度仅为O(n)。
    【算法三】
    算法二虽然优秀但实现较繁琐,不妨将其与算法一结合起来。
    考虑直接使用二分图匹配,对于算法二种在第一步删去的点,必然能求出正确的匹配,解不优只会发生在环中。尝试改进匹配算法:
    从大到小增广点i,寻找增广路时优先走向编号较小的点。
    证明:
    1.对于任一环,匹配的最后结果由最后增广的点决定,由上述算法的特性知,一定会找到该环内的最优解。
    2.对于环外一点,若存在经过该环的增广路,则该环内某X节点存在连向环外的边,那么它的度数超过2,矛盾,故不会因为环外某点的增广使得该环的匹配方案改变。
    虽然该算法时间复杂度为O(n^2),但思维复杂度与编程复杂度均很低,不失为考场上的好算法。
    【小结】
    算法一具有普适性,其核心思想也广泛应用于求字典序最小方案的各种问题中;算法二充分挖掘了本题中图的特殊性,时间复杂度达到理论下界;算法三主要利用了贪心思想,非常简洁,但其证明却不是那么显然。
    值得一提的是,算法三的正确性是基于该图的特殊性的,因而缺少可推广性,即不能解决一般二分图的字典序最小的匹配,下图即一个反例:
    e 使用算法三将求出(1,1)(2,3)(3,2),而最优解显然是(1,1)(2,2)(3,3)。
    此外,本题还可以利用2-SAT模型求解,但该模型在各方面均不优于二分图模型,故略去不提。

    Code

    // <transform.cpp> - Fri Sep 23 08:09:06 2016
    // This file is made by YJinpeng,created by XuYike's black technology automatically.
    // Copyright (C) 2016 ChangJun High School, Inc.
    // I don't know what this program is.
    
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #define MOD 1000000007
    #define INF 1e9
    using namespace std;
    typedef long long LL;
    const int MAXN=100010;
    const int MAXM=100010;
    inline int max(int &x,int &y) {return x>y?x:y;}
    inline int min(int &x,int &y) {return x<y?x:y;}
    inline int gi() {
    	register int w=0,q=0;register char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')q=1,ch=getchar();
    	while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
    	return q?-w:w;
    }
    int n,k,t[5],match[MAXN];
    vector<int>b[MAXN];bool f[MAXN];
    void work(int i,int a){
        int b=i+a;
        if(b<n)t[++k]=n+b;b=i-a;
        if(b>=0)t[++k]=n+b;
    }
    inline void add(int v,int u){
        b[u].push_back(v);b[v].push_back(u);
    }
    inline bool dfs(register int x){
        if(f[x])return 0;
        int num=b[x].size();f[x]=true;
        for(int i=0;i<num;i++){
            int nex=b[x][i];
            if(match[nex]==-1||dfs(match[nex])){
                match[x]=nex;match[nex]=x;f[x]=0;return 1;
            }
        }f[x]=0;
        return 0;
    }
    void pri(){printf("No Answer");exit(0);}
    int main()
    {
    	freopen("transform.in","r",stdin);
    	freopen("transform.out","w",stdout);
        n=gi();
        for(int i=0;i<n;i++){
            k=0;int a=gi();work(i,a);
            work(i,n-a);
            sort(t+1,t+1+k);for(int o=1;o<=k;o++)add(i,t[o]);
        }
        for(int i=0;i<MAXN;i++)match[i]=-1;
        for(int i=n-1;i>=0;i--)
            if(match[i]==-1)if(!dfs(i))pri();
        for(int i=0;i<n-1;i++)printf("%d ",match[i]-n);
        printf("%d",match[n-1]-n);
    	return 0;
    }
    
    
  • 相关阅读:
    leetcode701. Insert into a Binary Search Tree
    leetcode 958. Check Completeness of a Binary Tree 判断是否是完全二叉树 、222. Count Complete Tree Nodes
    leetcode 110. Balanced Binary Tree
    leetcode 104. Maximum Depth of Binary Tree 111. Minimum Depth of Binary Tree
    二叉树
    leetcode 124. Binary Tree Maximum Path Sum 、543. Diameter of Binary Tree(直径)
    5. Longest Palindromic Substring
    128. Longest Consecutive Sequence
    Mac OS下Android Studio的Java not found问题,androidfound
    安卓 AsyncHttpClient
  • 原文地址:https://www.cnblogs.com/YJinpeng/p/5907436.html
Copyright © 2020-2023  润新知