• UVA 658 It's not a Bug, it's a Feature! (最短路,经典)


    题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢。但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了:要打多久才能无bug?(同1补丁可重复打)

    分析:

      n<=20,那么用位来表示bug的话有220=100万多一点。不用建图了,图实在太大了,用位图又不好玩。那么直接用隐式图搜索(在任意点,只要满足转移条件,任何状态都能转)。

      但是有没有可能每个状态都要搜1次啊?那可能是100万*100万啊,这样出题还有解么?大部分状态是怎么打补丁都到不了的,但是具体要说是多少个也不能这么说吧,这个分析可能也太麻烦了,设计100个补丁能将n个1打成所有状态都覆盖就差不多超时了。(出题人应该不会这么精明,忽略这个问题)

      那么用位表示状态要怎么办?类似于状态压缩的感觉,每个bug有3种可能(必存在,必不存在,无所谓),只要40个位搞定,但是两个位表示1个bug状态也太麻烦了吧?那就开两个数组咯,配合表示就行了,丝毫没有省空间!!但是容易看了。但是这么设计使得在匹配的时候神速啊。

    思路:

      一开始所有bug是存在的,所以有sta=末尾n个1。接着我们要将其打成sta=0,任务艰巨,赶紧开始。

      (1)首先求状态的上限up。将1左移n个位置再减少1。

      (2)dijkstra来穷举每个状态,即0~up。用优先队列来优化它,一旦距离dist有更新,就进队(这么像SPFA!其实用了优先队列,一点不像,只要vis[该点]=1,那就忽略它,而spfa不忽略)。

      (3)当队列不空一直循环,直到循环了up次,或者可达状态全部遍历过了,就退出了,直接检查dist[0]是否为无穷大。

    难点:

      其实这题考的不是SSSP,而是位运算的设计。

      (1)如何检查m个bug种哪些是可以转移的?

        数组pat_r1[i]表示第i个补丁需要哪些bug必须存在,存在则该位为1;

        数组pat_r2[i]表示第i个补丁对那些bug无所谓,无所谓的位为0。

        假设本状态为flag,判断第j个补丁是否可以打,应该这样:

          int res=(flag^pat_r1[j]);   //异或完,满足要求的(即相同的)位会为0(无所谓的先不管)。
          res&=pat_r2[j];        //将无所谓的位全部置为0。
          if(res==0) return true;   //满足要求

      (2)如何获取转移后的状态?

        数组pat_o1[i]表示第i个补丁打完后输出的哪些bug依然存在,存在则该位为1;

        数组pat_o2[i]表示第i个补丁打完后输出的哪些bug依然不变,不会变的位为1。

        假设本状态为flag,打完补丁j 输出的结果应该是:

          int tmp=(flag&pat_o2[j]);    //将不变的取出来
          tmp+=pat_o1[j];         //将不变的补回去
          return tmp;          //打完了

      1 #include <bits/stdc++.h>
      2 #define LL long long
      3 #define pii pair<int,int>
      4 using namespace std;
      5 const int N=100+5;
      6 const int INF=0x7f7f7f7f;
      7 int pat_r1[N];   //补丁所需要的要求1
      8 int pat_r2[N];   //补丁所需要的要求2,记录无所谓
      9 int val[N];      //权值
     10 int pat_o1[N];   //打完补丁后的产出1
     11 int pat_o2[N];   //打完补丁后的产出2,记录不变
     12 int dist[1200000];   //表示状态
     13 bool vis[1200000];  
     14 int bugs, patches, v;
     15 int res, tmp;    //临时变量
     16 
     17 /*
     18 int cal()   //超时!!未优化的dijkstra。
     19 {
     20     memset(dist,0x7f,sizeof(dist));
     21     memset(vis,0,sizeof(vis));
     22 
     23     int t=bugs, up=1;
     24     while(t--)  up+=up;
     25     dist[--up]=0;
     26     for(int i=up; i>=0; i--)
     27     {
     28         int small=INF, flag=INF;
     29         for(int j=0; j<=up; j++)  //在状态j中找dist最短
     30         {
     31             if(!vis[j]&&dist[j]<small)
     32             {
     33                 flag=j;         //标记该状态
     34                 small=dist[j];  //snall保存所耗时间
     35             }
     36         }
     37         if(flag==INF)   return -1;  //找不到
     38 
     39         vis[flag]=1;
     40 
     41 
     42         for(int j=1; j<=patches; j++)   //扫描每个补丁
     43         {
     44             //检查是否满足条件
     45             res=(flag^pat_r1[j]);   //异或完,满足要求的会为0(除了无所谓的)。
     46             res&=pat_r2[j];         //将无所谓的位全部置为0。
     47 
     48             if( !res  )    //只要为0就是满足条件
     49             {
     50                 tmp=(flag&pat_o2[j]);   //将不变的取出来
     51                 tmp+=pat_o1[j];         //将不变的补回去
     52                 if( dist[tmp]>dist[flag]+val[j] )    //时间比较短的
     53                 {
     54                     dist[tmp]=dist[flag]+val[j];
     55                     if(!tmp)   return dist[tmp];  //bug全部修复
     56                 }
     57             }
     58         }
     59     }
     60     return -1;  //修不了
     61 
     62 
     63 }
     64 
     65 */
     66 
     67 
     68 int can_use(int flag, int j)
     69 {
     70     //检查是否满足条件
     71     int res=(flag^pat_r1[j]);   //异或完,满足要求的会为0(除了无所谓的)。
     72     res&=pat_r2[j];         //将无所谓的位全部置为0。
     73     if(res==0)    return true;
     74     return false;
     75 }
     76 
     77 int get_sta(int flag, int j)
     78 {
     79     //获取将要更新的状态
     80     int tmp=(flag&pat_o2[j]);   //将不变的取出来
     81     tmp+=pat_o1[j];             //将不变的补回去
     82     return tmp;
     83 }
     84 
     85 int cal()
     86 {
     87     priority_queue<pii, vector<pii>, greater<pii> > que;
     88 
     89     memset(vis, 0, sizeof(vis));
     90     memset(dist, 0x7f, sizeof(dist));
     91 
     92     int t=bugs, up=1;
     93     while(t--)  up+=up; //获取上限
     94     dist[--up]=0;
     95 
     96     que.push(make_pair(0,up));
     97     while(!que.empty())
     98     {
     99         int flag=que.top().second; que.pop();
    100         if(vis[flag]) continue;     //重复
    101         vis[flag]=1;
    102 
    103         for(int j=1; j<=patches; j++)   //扫描每个补丁
    104         {
    105             int tmp=get_sta(flag, j);
    106             if( can_use(flag, j) && dist[tmp]>dist[flag]+ val[j] )    //只要为0就是满足条件
    107             {
    108                 dist[tmp]=dist[flag]+ val[j];
    109                 que.push(make_pair(dist[tmp],tmp));
    110             }
    111         }
    112     }
    113     return dist[0];
    114 }
    115 
    116 int main()
    117 {
    118     freopen("input.txt", "r", stdin);
    119     char s[50], s2[50];
    120     int Case=0;
    121     while(scanf("%d %d", &bugs, &patches ), bugs||patches)
    122     {
    123         for(int i=1; i<=patches; i++)
    124         {
    125             scanf("%d %s %s", &v, s, s2);
    126             val[i]=v;
    127             pat_r1[i]= pat_r2[i]= 0;
    128             for(int j=1; j<=bugs; j++)  //要求
    129             {
    130                 pat_r1[i]<<=1;
    131                 pat_r2[i]<<=1;
    132 
    133                 if(s[j-1]=='+')       //'+'用1表示,'-'用0表示(直接移位,不用处理)
    134                     pat_r1[i]++;
    135                 if(s[j-1]!='0')       //无所谓用0表示
    136                     pat_r2[i]++;
    137             }
    138 
    139             pat_o1[i]= pat_o2[i]= 0;
    140             for(int j=1; j<=bugs; j++)  //输出
    141             {
    142                 pat_o1[i]<<=1;
    143                 pat_o2[i]<<=1;
    144                 if(s2[j-1]=='+')  //有bug就1,无bug为0
    145                     pat_o1[i]++;
    146                 if(s2[j-1]=='0')  //不变为1
    147                     pat_o2[i]++;
    148             }
    149         }
    150         printf("Product %d
    ",++Case);
    151         int ans=cal();
    152         if(ans<INF) printf("Fastest sequence takes %d seconds.
    
    ", ans );
    153         else     printf("Bugs cannot be fixed.
    
    ");
    154     }
    155     return 0;
    156 }
    AC代码177ms
     1 #include <bits/stdc++.h>
     2 #define LL long long
     3 #define pii pair<int,int>
     4 using namespace std;
     5 const int N=100+5;
     6 const int INF=0x7f7f7f7f;
     7 int pat_r1[N], pat_r2[N], pat_o1[N], pat_o2[N], val[N], dist[1200000], vis[1200000];
     8 int bugs, patches, v;
     9 
    10 int can_use(int flag, int j)
    11 {
    12     int res=(flag^pat_r1[j]);   //异或完,满足要求的会为0(除了无所谓的)。
    13     res&=pat_r2[j];         //将无所谓的位全部置为0。
    14     if(res==0)    return true;
    15     return false;
    16 }
    17 
    18 int get_sta(int flag, int j)
    19 {
    20     int tmp=(flag&pat_o2[j]);   //将不变的取出来
    21     tmp+=pat_o1[j];             //将不变的补回去
    22     return tmp;
    23 }
    24 
    25 
    26 
    27 int cal()
    28 {
    29     priority_queue<pii, vector<pii>, greater<pii> > que;
    30     memset(vis, 0, sizeof(vis));
    31     memset(dist, 0x7f, sizeof(dist));
    32     int up=1;
    33     while(bugs--)  up+=up;
    34     dist[--up]=0;
    35 
    36     que.push(make_pair(0,up));
    37     while(!que.empty())
    38     {
    39         int flag=que.top().second; que.pop();
    40         vis[flag]=1;
    41         for(int j=1; j<=patches; j++)   //扫描每个补丁
    42         {
    43             int tmp=get_sta(flag, j);
    44             if( can_use(flag, j) && dist[tmp]>dist[flag]+ val[j] )    //只要为0就是满足条件
    45             {
    46                 dist[tmp]=dist[flag]+ val[j];
    47                 if(!vis[tmp])    que.push(make_pair(dist[tmp],tmp));
    48                 //if(!tmp)   return dist[0];  //不能这么做,可能还有更新,这只是更新第一次而已,至少要n次
    49             }
    50         }
    51     }
    52     return dist[0];
    53 }
    54 
    55 int main()
    56 {
    57     freopen("input.txt", "r", stdin);
    58     char s[50], s2[50];
    59     int Case=0;
    60     while(scanf("%d %d", &bugs, &patches ), bugs||patches)
    61     {
    62         for(int i=1; i<=patches; i++)
    63         {
    64             scanf("%d %s %s", &v, s, s2);
    65             val[i]=v;
    66             pat_r1[i]= pat_r2[i]= pat_o1[i]= pat_o2[i]= 0;
    67             for(int j=1; j<=bugs; j++)
    68             {
    69                 pat_r1[i]<<=1,pat_r2[i]<<=1,pat_o1[i]<<=1,pat_o2[i]<<=1;
    70                 if(s[j-1]=='+')     pat_r1[i]++;
    71                 if(s[j-1]!='0')     pat_r2[i]++;
    72                 if(s2[j-1]=='+')    pat_o1[i]++;
    73                 if(s2[j-1]=='0')    pat_o2[i]++;
    74             }
    75         }
    76         int ans=cal();
    77         if(ans<INF) printf("Product %d
    Fastest sequence takes %d seconds.
    
    ",++Case, ans );
    78         else     printf("Product %d
    Bugs cannot be fixed.
    
    ",++Case);
    79     }
    80     return 0;
    81 }
    短码AC版本
  • 相关阅读:
    CF687D Dividing Kingdom II
    图论——EK算法
    P6082 [JSOI2015]salesman
    联合权值——树上问题2014noip
    P2071 座位安排——二分图最大匹配
    匈牙利优化时间戳的正确性
    P1541 乌龟棋——线性动规
    P1858 多人背包
    P3558 [POI2013]BAJ-Bytecomputer——线性动归
    P2303 [SDOI2012] Longge 的问题
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4623121.html
Copyright © 2020-2023  润新知