事情的起因是我需要从域里面读出所有被禁用的域账号作清理。
然后发现域账号的属性里有一项userAccountControl表示账号的启用状态的。
1 该项的状态值允许有多个,并且只存储它们的和。
2 所有状态值为2的n次方。(1,2,4,8...)
附微软官方资料
属性标志     十六进制值   十进制值 
SCRIPT       0x0001     1 
ACCOUNTDISABLE 0x0002     2 
HOMEDIR_REQUIRED 0x0008   8 
LOCKOUT         0x0010    16 
PASSWD_NOTREQD   0x0020   32 
PASSWD_CANT_CHANGE 0x0040 64 
ENCRYPTED_TEXT_PWD_ALLOWED 0x0080 128 
TEMP_DUPLICATE_ACCOUNT 0x0100 256 
NORMAL_ACCOUNT 0x0200 512 
利用ladp协议读取出来的总和值,如何反推出来由哪几个状态组合而成的?
事实我上的目的无非就是想确认账号里有没有被禁用状态(值为2)。
注:一个用户被禁用后,肯定有2的状态,但还会有若干个其它状态。最后归纳为数学问题,已知数列为2的那次方(1,2,4,8,16...)
从中抽取任意个(各不相同)相加,已知和为N,如何反推出来这几个加数是多少?

解决方案 »

  1.   

    private List<int> GetList(int sum)
                {
                    List<int> list = new List<int>();
                    for (int i = 1; ; i *= 2)
                    {
                        bool flag = (sum & i) != 0;
                        if (flag)
                        {
                            list.Add(i);
                        }
                        else
                            break;
                    }
                    return list;
                }调用
    //调用
                    List<int> temp=GetList(63);
                    /*
                     * 1 2 4
                     */ 
      

  2.   

    需要修正一下,如果是任意的之和的话,上面只是顺序输出
    private List<int> GetList(int sum)
                {
                    List<int> list = new List<int>();
                    for (int i = 1; i<sum; i *= 2)
                    {
                        bool flag = (sum & i) != 0;
                        if (flag)
                        {
                            list.Add(i);
                        }
                    }
                    return list;
                }
      

  3.   

    分析:
    N值有两种结果:奇数或偶数。凡是与1相加的必定为奇数,其他的相加则必定是偶数
    if(N is 奇数)
    {
       N = N-1;..............//此时这个N必定是2的n次方的组合相加
    }
    else if(N is 偶数)
    {
       .....//这个N也将是2的n次方相加
    }
    ...至于大括号里要如何取处理还没想到
      

  4.   

    CRIPT       0x0001     1 
    ACCOUNTDISABLE 0x0002     2 
    HOMEDIR_REQUIRED 0x0008   8 
    LOCKOUT         0x0010    16 
    PASSWD_NOTREQD   0x0020   32 
    PASSWD_CANT_CHANGE 0x0040 64 
    ENCRYPTED_TEXT_PWD_ALLOWED 0x0080 128 
    TEMP_DUPLICATE_ACCOUNT 0x0100 256 
    NORMAL_ACCOUNT 0x0200 512 
    把这些值转为二进制,你就清楚了1 =  1; 
    2 = 10 
    4 = 100;
    8 = 1000;
    16=10000;
    32=100000;
    64 
    只要和相应位 与运算,就可以得出结果
    例如 求 ACCOUNTDISABLE 
     if(accountdisable&0x2!=0)
       禁用
     else
      启用
      

  5.   

    有个比较笨的方法,假设任意个加数从小到大排列,分别为2^n1、2^n2...2^nx, 它们的加和为sum
    可以证明sum肯定小于2^(nx +1 ),且大于或等于2^nx。
    所以,nx的值为(long)Math.Log(2,sum);
    将sum - 2^x 得到 sum1, 循环用上述方法,直到刚好有一个2^ni等于sumk或者sumk=1。代码才刚学,思路先奉上,希望楼主喜欢
      

  6.   

    sum & i 这个啥意思 没搞懂哈。。
      

  7.   

    =======================
        这是我的代码 
    我测了一下,试了几个值,结果都是正确的。
    =======================
    static void Main(string[] args)
            {
                int sum;
                string strSum = Console.ReadLine();
                sum = Convert.ToInt32(strSum);
                List<int> ln = new List<int>();
                int n;
                while(sum>0)
                {       
                    n = (int)Math.Log(sum, 2);
                    sum -= (int)Math.Pow(2, n);
                    ln.Add(n);
                }
                if (ln.Count>0)
                {
                    for (int i = 0; i < ln.Count;i++ )
                    {
                        Console.WriteLine(ln[i]);
                    }
                }
                Console.ReadKey();
            }
      

  8.   

    二进制展开之后你就会发现一个很长的二进制。
    每位代表一个开关。
    你只需要做右移位->判断类型->加入属性列表。就行了。
      

  9.   

    位与嘛,这是老式的状态记录方式,比如你想知道X里包含4没有,那就是  if(X & 4 == 4){...}