算法引论--寻找一对一映射

来源:互联网 发布:上海男人 知乎 编辑:程序博客网 时间:2024/05/21 07:12

寻找一对一映射

令f是一个把有限集映射到自身的函数(即A中的每一个元素都被映射到A中的另一个元素)。为了简单起见,用整数0到n来表示A中的元素,假定函数f用数组f[0..n]来表示,f[i]中占据的是f(i)的值。如果对每一个元素j,至多存在一个元素i映射到j,则称f是一个一对一的函数。函数f可以用图的形式来表示。

如果f原本就是一对一的,则整个集合A满足条件,且A必然也是最大的。另一方面,对于某些i,j,存在f[i] = f[j],那么S就不可能同时包含i和j,对于他们之间要消除哪一个,并不是任意的。例如:消除3,由于1映射到3,1也必须要消除,那么2也必须跟着1的消除而消除。但这样的子集不是最大的。

在我们决定如何把问题简化到小问题上,还可以做一些处理。比如,通过寻找一个元素是否属于S来减小问题的规模。

实现:用一个计数器c[i]来记录在每一个元素i。直觉上,c[i]等于映射到i的元素的数目。对于所有的i,通过在n个步骤内扫描数组并递增相应的计数器,可以计算出c[i],然后把所有计数器为零的元素放进一个队列,每一个步里,把元素j从队列中删除,并递减c[f[j]],同时如果c[f[j]]=0,把f[j]放进队列。

`    import java.util.ArrayDeque;    import java.util.ArrayList;    import java.util.Queue;    public class Mapping {    public ArrayList<Integer> algorithm_mapping (int[] f, int n) {    if(f == null || f.length == 0)        return null;     ArrayList<Integer> s = new ArrayList<Integer>();    int[] c = new int[n]; //计数器    for (int i = 0; i < n; i++)        s.add(Integer.valueOf(i));    for(int i = 0; i < n; i++)        c[i] = 0;    for (int i = 0; i < n; i++)        c[f[i]]++;    Queue<Integer> queue = new ArrayDeque<Integer>();    for(int i = 0; i < n; i++) {        if (c[i] == 0)            queue.offer(i);        while(!queue.isEmpty()) {            Integer j = queue.poll();            if (s.remove(j))                c[f[j]]--;            if (c[f[j]] == 0)                queue.offer(f[j]);        }    }    return s;}public static void main(String[] args) {    // TODO Auto-generated method stub    Mapping m = new Mapping();    int[] f = new int[]{2,0,0,4,4,3,5};    ArrayList<Integer> result = m.algorithm_mapping(f,f.length);    System.out.println(result.toString());}

}

`
原创粉丝点击