关于位运算

 原帖地址http://hi.baidu.com/alpc43/blog/item/3cdbf054a8b18752574e0006.html

 

Description

Background
Today, there are quite a few cars, motorcycles, trucks and other vehicles out there on the streets that would seriously need some refurbishment. You have taken on this job, ripping off a few dollars from a major TV station along the way.
Of course, there's a lot of work to do, and you have decided that it's getting too much. Therefore you want to have the various jobs like painting, interior decoration and so on done by garages. Unfortunately, those garages are very specialized, so you need different garages for different jobs. More so, they tend to charge you the more the better the overall appearance of the car is. That is, a painter might charge more for a car whose interior is all leather. As those "surcharges" depend on what job is done and which jobs have been done before, you are currently trying to save money by finding an optimal order for those jobs.
Problem
Individual jobs are numbered 1 through n. Given the base price p for each job and a surcharge s (in US$) for every pair of jobs (i, j) with i != j, meaning that you have to pay additional $s for job i, if and only if job j was completed before, you are to compute the minimum total costs needed to finish all jobs.

Input

The first line contains the number of scenarios. For each scenario, an integer number of jobs n, 1 <= n <= 14, is given. Then follow n lines, each containing exactly n integers. The i-th line contains the surcharges that have to be paid in garage number i for the i-th job and the base price for job i. More precisely, on the i-th line, the i-th integer is the base price for job i and the j-th integer (j != i) is the surcharge for job i that applies if job j has been done before. The prices will be non-negative integers smaller than or equal to 100000.

Output

The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line:
"You have officially been pimped for only $p"
with p being the minimum total price. Terminate the output for the scenario with a blank line.

Sample Input

2
2
10 10
9000 10
3
14 23 0
0 14 0
1000 9500 14

Sample Output

Scenario #1:
You have officially been pimped for only $30

Scenario #2:
You have officially been pimped for only $42
 
 
  1. Source
  2. TUD Programming Contest 2005, Darmstadt, German----------------------------------------------------------------
  3. #include <stdio.h>
  4. #include <string.h>
  5. #define min(x,y) ((x)<(y)?(x):(y))
  6. int dp[1<<14];
  7. int cost[15][15];
  8. int main()
  9. {
  10. int cas,n;
  11. int i,j,k;
  12. int step=0;
  13. int max;
  14. scanf("%d",&cas);
  15. while(cas--)
  16.       scanf("%d",&n);
  17.    step++;
  18.       for(i=0;i<n;i++)
  19.     for(j=0;j<n;j++)
  20.       scanf("%d",&cost[i][j]);
  21.    memset(dp,1,sizeof(dp));
  22.    max=dp[0];
  23.    dp[0]=0;
  24.    for(i=0;i<(1<<n);++i)
  25.     if(dp[i]!=max)
  26.     {
  27.     for(j=0;j<n;++j)
  28.      if(!(i&(1<<j)))
  29.      {
  30.       int x=i|(1<<j);
  31.                   int now=0;
  32.      for(k=0;k<n;++k)
  33.       if(i&(1<<k))
  34.       {
  35.       
  36.         now+=cost[j][k];
  37.       }
  38.       dp[x]=min(dp[x],dp[i]+now);
  39.      }
  40.     }
  41.      int anwer=dp[(1<<n)-1];就是这里没有加结果出不了样例
  42.    for(i=0;i<n;i++)
  43.     anwer+=cost[i][i];
  44.      printf("Scenario #%d:/n",step);
  45.         printf("You have officially been pimped for only $%d/n/n",anwer);
  46. }
  47. return 0;
  48. }

位运算来表示状态的转移.....很有用.DP效率很高.但是要注意的问题是,位运算的优先级很低,必须要加括号!

位运算应用口诀和实例

位运算应用口诀
清零取反要用与,某位置一可用或
若要取反和交换,轻轻松松用异或

移位运算
要点 1 它们都是双目运算符,两个运算分量都是整形,结果也是整形。
     2 "<<" 左移:右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2。
     3 ">>"右移:右边的位被挤掉。对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统。
     4 ">>>"运算符,右边的位被挤掉,对于左边移出的空位一概补上0。

位运算符的应用 (源操作数s 掩码mask)
(1) 按位与-- &
1 清零特定位 (mask中特定位置0,其它位为1,s=s&mask)
2 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)
(2) 按位或-- |
    常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
(3) 位异或-- ^
1 使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)
2 不引入第三变量,交换两个变量的值 (设 a=a1,b=b1)
    目 标           操 作              操作后状态
a=a1^b1         a=a^b              a=a1^b1,b=b1
b=a1^b1^b1      b=a^b              a=a1^b1,b=a1
a=b1^a1^a1      a=a^b              a=b1,b=a1

二进制补码运算公式:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y:    ~(x-y|y-x)
x!=y:    x-y|y-x
x< y:    (x-y)^((x^y)&((x-y)^x))
x<=y:    (x|~y)&((x^y)|~(y-x))
x< y:    (~x&y)|((~x|y)&(x-y))//无符号x,y比较
x<=y:    (~x|y)&((x^y)|~(y-x))//无符号x,y比较

应用举例
(1) 判断int型变量a是奇数还是偶数           
a&1   = 0 偶数
       a&1 =   1 奇数
(2) 取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1
(3) 将int型变量a的第k位清0,即a=a&~(1<<k)
(4) 将int型变量a的第k位置1, 即a=a|(1<<k)
(5) int型变量循环左移k次,即a=a<<k|a>>16-k   (设sizeof(int)=16)
(6) int型变量a循环右移k次,即a=a>>k|a<<16-k   (设sizeof(int)=16)
(7)整数的平均值
对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:
int average(int x, int y)   //返回X,Y 的平均值
{   
     return (x&y)+((x^y)>>1);
}
(8)判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂
boolean power2(int x)
{
    return ((x&(x-1))==0)&&(x!=0);
}
(9)不用temp交换两个整数
void swap(int x , int y)
{
    x ^= y;
    y ^= x;
    x ^= y;
}
(10)计算绝对值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ;        //or: (x+y)^y
}
(11)取模运算转化成位运算 (在不产生溢出的情况下)
         a % (2^n) 等价于 a & (2^n - 1)
(12)乘法运算转化成位运算 (在不产生溢出的情况下)
         a * (2^n) 等价于 a<< n
(13)除法运算转化成位运算 (在不产生溢出的情况下)
         a / (2^n) 等价于 a>> n
        例: 12/8 == 12>>3
(14) a % 2 等价于 a & 1       
(15) if (x == a) x= b;
            else x= a;
        等价于 x= a ^ b ^ x;
(16) x 的 相反数 表示为 (~x+1)
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值