• UVA 10159


    http://blog.csdn.net/metaphysis/article/details/6926997

    先向作者表达一下敬佩吧,十分巧妙地利用了状态压缩。

    这道题有点组合数学的味道,当一个格子选后,就把行最大值与格子值相等的行标志位置1.这样,当111111111111即是求的状态了。

    这样,可以设一个sum[MAX-1]的数组来对应每一种状态,通过位的或运算的关系来实现状态转移。实在妙极。

    原作者代码:

      1 // [解题方法]
      2 // 根据每个小格所属行的限制来确定该小格内的最大值,然后检测是否满足每行的最大值要求,若不满足,则
      3 // 不可能,若满足,求其最大值。对于最小可能值,可以通过动态规划来获得。
      4 
      5 #include <iostream>
      6 #include <cstring>
      7 #include <sstream>
      8 
      9 using namespace std;
     10 
     11 #define MAXLINES 12        // 行数。
     12 #define MAXCELLS 48        // 小格总个数。
     13 #define MAXINT 10
     14 #define EMPTY (-1)
     15 #define MAXTYPES (1 << 12)
     16 
     17 int maxValue[MAXLINES];        // 每行的最大值。
     18 int cells[MAXCELLS];        // 小格内数字值。
     19 
     20 // 每个小格属于那些行,行使用题目所给的 A - I 表示。从 0 开始,按从上到下,从左至右的顺序编号。
     21 string belongs[MAXCELLS] = {
     22     "EL",     // 0
     23     "EK", "EL", "FL",    // 1 - 3
     24     "AI", "AI", "AJ", "AEJ", "AEK", "AFK", "AFL", "AGL", "AG", "AH", "AH",    // 4 - 14
     25     "BI", "BEI", "BEJ", "BFJ", "BFK", "BGK", "BGL", "BHL", "BH",    // 15 - 23
     26     "CE", "CEI", "CFI", "CFJ", "CGJ", "CGK", "CHK", "CHL", "CL",    // 24 - 32
     27     "DE", "DE", "DF", "DFI", "DGI", "DGJ", "DHJ", "DHK", "DK", "DL", "DL",    // 33 - 43
     28     "GI", "HI", "HJ",    // 44 - 46
     29     "HI"    // 47
     30 };
     31 
     32 // 非 EMPTY 元素值表示组成该行的小格编号,从 0 开始,按从上到下,从左至右的顺序编号。
     33 int lines[MAXLINES][MAXLINES - 1] = {
     34     { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
     35     { 15, 16, 17, 18, 19, 20, 21, 22, 23, EMPTY, EMPTY },
     36     { 24, 25, 26, 27, 28, 29, 30, 31, 32, EMPTY, EMPTY },
     37     { 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43 },
     38     { 0, 1, 2, 7, 8, 16, 17, 24, 25, 33, 34 },
     39     { 3, 9, 10, 18, 19, 26, 27, 35, 36, EMPTY, EMPTY },
     40     { 11, 12, 20, 21, 28, 29, 37, 38, 44, EMPTY, EMPTY },
     41     { 13, 14, 22, 23, 30, 31, 39, 40, 45, 46, 47 },
     42     { 4, 5, 15, 16, 25, 26, 36, 37, 44, 45, 47 },
     43     { 6, 7, 17, 18, 27, 28, 38, 39, 46, EMPTY, EMPTY },
     44     { 1, 8, 9, 19, 20, 29, 30, 40, 41, EMPTY, EMPTY },
     45     { 0, 2, 3, 10, 11, 21, 22, 31, 32, 42, 43 }
     46 };
     47 
     48 // 动态规划求最小可能值,这里使用了 tmp
     49 // 数组,在原 sum 数组计算的结果先填写在 tmp 数组上,以免持续在 sum 数组上操作引起混乱,同时
     50 // 注意最小可能值方案一定是将最大可能值方案中某些小格置 0 而得来的(为什么这样,可以思考一下!)。
     51 int dynamic_programming()
     52 {
     53     int sum[MAXTYPES], tmp[MAXTYPES];
     54     
     55     // 初始化。
     56     memset(sum, EMPTY, sizeof(sum));
     57     
     58     // 当无任何行匹配时,和最小值为 0.
     59     sum[0] = 0;
     60 
     61     for (int i = 0; i < MAXLINES; i++)
     62     {
     63         // 在副本上操作。
     64         memcpy(tmp, sum, sizeof(sum));
     65         for (int j = 0; j < MAXTYPES; j++)
     66             if (sum[j] > EMPTY)
     67             {
     68                 for (int k = 0; k < MAXLINES - 1; k++)
     69                 {
     70                     // 空小格,该行已处理完毕。
     71                     if (lines[i][k] == EMPTY)
     72                         break;
     73 
     74                     // 只需处理值为该行最大值的小格。
     75                     if (cells[lines[i][k]] == maxValue[i])
     76                     {
     77                         int t = j;
     78                         // cell 表示该小格属于哪些行。
     79                         string cell = belongs[lines[i][k]];
     80                         for (int c = 0; c < cell.length(); c++)
     81                             // 注意条件!只有当小格的值满足了某行的最大值要求,才计
     82                             // 入 t。t 的意义是该小格值满足了哪些行的最大值要求。
     83                             // 使用匹配的行的序号作为移位值来生成一个唯一表示该行的
     84                             // 整数。
     85                             if (cells[lines[i][k]] == maxValue[cell[c] - 'A'])
     86                                 t = t | (1 << (cell[c] - 'A'));
     87 
     88                         // 更新和的最小值。
     89                         if (tmp[t] > EMPTY)
     90                             tmp[t] = min(tmp[t], sum[j] + maxValue[i]);
     91                         else
     92                             tmp[t] = sum[j] + maxValue[i];
     93                     }
     94                 }
     95             }
     96 
     97         // 获得副本上的结果。
     98         memcpy(sum, tmp, sizeof(tmp));
     99     }
    100 
    101     return sum[MAXTYPES - 1];
    102 }
    103 
    104 int main(int ac, char *av[])
    105 {
    106     string line;
    107 
    108     while (getline(cin, line))
    109     {
    110         // 读入每行的最大值限制。
    111         istringstream iss(line);
    112         for (int i = 0; i < MAXLINES; i++)
    113             iss >> maxValue[i];
    114 
    115         // 根据限制,获得每个方格的最大值。
    116         memset(cells, 0, sizeof(cells));
    117         for (int i = 0; i < MAXCELLS; i++)
    118         {
    119             int value = MAXINT;
    120             for (int j = 0; j < belongs[i].length(); j++)
    121                 value = min(value,
    122                     maxValue[belongs[i][j] - 'A']);
    123 
    124             cells[i] = value;
    125         }
    126 
    127         // 检查方格的值是否满足最大值要求。
    128         bool noSolution = false;
    129         for (int i = 0; i < MAXLINES; i++)
    130         {
    131             int tmp = 0;
    132             for (int j = 0; j < MAXLINES - 1; j++)
    133             {
    134                 if (lines[i][j] == EMPTY)
    135                     break;
    136                 tmp = max(tmp, cells[lines[i][j]]);
    137             }
    138             
    139             if (tmp != maxValue[i])
    140             {
    141                 noSolution = true;
    142                 break;
    143             }
    144         }
    145         
    146         // 输出。
    147         if (noSolution)
    148             cout << "NO SOLUTION" << endl;
    149         else
    150         {
    151             // 数字和最大可能值。
    152             int maxSum = 0;
    153             for (int i = 0; i < MAXCELLS; i++)
    154                 maxSum += cells[i];
    155 
    156             // 数字和最小可能值。最小可能值的含义是取尽可能少的数字,使得满足所有
    157             // 最大值的要求。由于前面的最大可能值方案中已经包含了最小可能值的方案,
    158             // 需要将一些小格置为 0 来获得最小可能值,如果小格置 0 的数目越多,
    159             // 当然最后和更小,那么就要求一个小格的数字尽可能满足多行的最大值要求,
    160             // 这样可以减少非零数字的使用,可以使用动态规划找最小值。
    161             int minSum = dynamic_programming();
    162 
    163             cout << minSum << " " << maxSum << endl;
    164         }
    165     }
    166 
    167     return 0;
    168 }
    View Code

    可怜不知为什么,我的代码竟没能AC。算了,领悟到这样绝妙的思想,已经很满足了。

      1 #include <iostream>  
      2 #include <cstring> 
      3 #include <cstdio>
      4 #include <string> 
      5 #include <sstream>
      6 
      7 #define EMPTY (-1)
      8 #define MAXLINES 12     // 行数。  
      9 #define MAXCELLS 48     // 小格总个数。  
     10 #define MAXLEN (1<<12)
     11 
     12 using namespace std;
     13 
     14 int lines[MAXLINES][MAXLINES - 1] = {  
     15     { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },  
     16     { 15, 16, 17, 18, 19, 20, 21, 22, 23, EMPTY, EMPTY },  
     17     { 24, 25, 26, 27, 28, 29, 30, 31, 32, EMPTY, EMPTY },  
     18     { 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43 },  
     19     { 0, 1, 2, 7, 8, 16, 17, 24, 25, 33, 34 },  
     20     { 3, 9, 10, 18, 19, 26, 27, 35, 36, EMPTY, EMPTY },  
     21     { 11, 12, 20, 21, 28, 29, 37, 38, 44, EMPTY, EMPTY },  
     22     { 13, 14, 22, 23, 30, 31, 39, 40, 45, 46, 47 },  
     23     { 4, 5, 15, 16, 25, 26, 36, 37, 44, 45, 47 },  
     24     { 6, 7, 17, 18, 27, 28, 38, 39, 46, EMPTY, EMPTY },  
     25     { 1, 8, 9, 19, 20, 29, 30, 40, 41, EMPTY, EMPTY },  
     26     { 0, 2, 3, 10, 11, 21, 22, 31, 32, 42, 43 }  
     27 };  
     28 
     29 string belongs[MAXCELLS] = {  
     30     "EL",   // 0  
     31     "EK", "EL", "FL",   // 1 - 3  
     32     "AI", "AI", "AJ", "AEJ", "AEK", "AFK", "AFL", "AGL", "AG", "AH", "AH",  // 4 - 14  
     33     "BI", "BEI", "BEJ", "BFJ", "BFK", "BGK", "BGL", "BHL", "BH",    // 15 - 23  
     34     "CE", "CEI", "CFI", "CFJ", "CGJ", "CGK", "CHK", "CHL", "CL",    // 24 - 32  
     35     "DE", "DE", "DF", "DFI", "DGI", "DGJ", "DHJ", "DHK", "DK", "DL", "DL",  // 33 - 43  
     36     "GI", "HI", "HJ",   // 44 - 46  
     37     "HI"    // 47  
     38 };
     39 
     40 int maze[50];
     41 int maxtype[15],tes[15];
     42 int sum[MAXLEN],tmp[MAXLEN];
     43 
     44 int dp(){
     45     memset(sum,-1,sizeof(sum));
     46     sum[0]=0;
     47     for(int i=0;i<12;i++){
     48         memcpy(tmp, sum, sizeof(sum));
     49         for(int k=0;k<MAXLEN;k++){
     50             if(sum[k]==-1)
     51             continue;
     52             for(int p=0;lines[i][p]!=EMPTY&&p<MAXLINES-1;p++){
     53             //    if(maze[lines[i][p]]!=maxtype[i]) continue;
     54                 int t=k;
     55                 for(int q=0;q<belongs[lines[i][p]].length();q++){
     56                     if(maze[lines[i][p]]==maxtype[belongs[lines[i][p]][q]-'A'])
     57                     t=t|(1<<(belongs[lines[i][p]][q]-'A'));
     58                 }
     59                 if(tmp[t]==-1){
     60                     tmp[t]=sum[k]+maxtype[i];
     61                 }
     62                 else {
     63                     tmp[t]=min(tmp[t],sum[k]+maxtype[i]);
     64                 }
     65             }
     66         }
     67         memcpy(sum, tmp, sizeof(tmp));
     68     //    cout<<maxtype[i]<<endl;
     69     }
     70     return sum[MAXLEN-1];
     71 }
     72 
     73 int main(){   
     74 string line;  
     75   
     76     while (getline(cin, line))  
     77     {  
     78         // 读入每行的最大值限制。  
     79         istringstream iss(line);  
     80         for (int i = 0; i < MAXLINES; i++)  
     81             iss >> maxtype[i];
     82         memset(tes,-1,sizeof(tes));
     83         for(int i=0;i<50;i++)
     84         maze[i]=100;
     85         int ans=0;
     86         for(int i=0;i<48;i++){
     87             for(int k=0;k<belongs[i].length();k++){
     88                 maze[i]=min(maze[i],maxtype[belongs[i][k]-'A']);
     89             }
     90             for(int k=0;k<belongs[i].length();k++)
     91                 tes[belongs[i][k]-'A']=max(maze[i],tes[belongs[i][k]-'A']);
     92             ans+=maze[i];
     93         }
     94         bool flag=true;
     95         for(int i=0;i<12;i++)
     96         if(tes[i]!=maxtype[i]){
     97             flag=false;
     98             break;
     99         }
    100         if(!flag){
    101             cout<<"NO SOLUTION"<<endl;
    102             continue;
    103         }
    104         int res=dp();
    105         cout<<res<<' '<<ans<<endl;
    106     }
    107     return 0;
    108 }
    View Code
  • 相关阅读:
    Python中append和extend的区别
    python学习 day19
    python学习 day18
    QT下编写使用for循环动态添加刻选择时间类型的按钮(记录一下)
    QT mingw编译器下使用snap7库与西门子200smart-PLC(网口)通信实现代码
    看着挺胖的大胖猫
    QT添加软键盘后,QDialog设置模态后软键盘没响应解决办法
    QT程序打包在别的电脑上运行提示“api-ms-win-crt-runtime-|1-1-0.dll"可能与您正在运行的Window版本不兼容。。。。。
    Qt使用WM_COPYDATA消息进行进程通信
    离线百度地图,QT添加按钮点击切换卫星地图和街道地图
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/3871169.html
Copyright © 2020-2023  润新知