zoukankan      html  css  js  c++  java
  • DP---基本思想 具体实现 经典题目 POJ1160 POJ1037

    POJ1160, post office。动态规划的经典题目。呃,又是经典题目,DP部分的经典题目怎就这么多。木有办法,事实就这样。

    求:在村庄内建邮局,要使村庄到邮局的距离和最小。

    设有m个村庄,分别为 V1 V2 V3 … Vm, 要建n个邮局,分别为P1 P2 P3 … Pn。

    在DP的问题中,经常有从m个物体中选n个物体的情况,本题显然也属于这种情况。一般可以这样考虑:假设已经选了1个,那么就成了在m-1个中选n-1个的问题了。

    对于此题,也可以考虑先建一个邮局。建在哪里呢?不妨设,该邮局建在Vk+1..Vm之间的某个村庄里,而且规定Vk+1..Vm之间再不允许建立其他邮局了。因此,剩下的n-1个邮局必然出现在V1..Vk之间的村庄内,这样问题就转换成:在前k个村庄里选n-1个邮局的问题。

    设dp( m,n )表示在V1…Vm之间建立n个邮局时的最短距离。

    L( i, j )表示在Vi…Vj之间建立一个邮局的最短距离。

    状态转换方程:

    dp( m,n ) = Min( dp( k,n-1 ) + L( k+1,m ) ),    其中:1 <= k<m

    编程实现:没啥说的,具体看代码。

     

    POJ1037, a decorative fence。这个题绝对不是入门级的,如果能独立做出来,那已经很NB了。嘿嘿,这一大段英文,先要把题目看懂就得费些气力。

    问题:有n个长度不同的木条,现在按照类似字典顺序(长度小的排在前)对这n个木条排序,求第m个图像是什么?

    设这n个木条分别为S1 S2 S3…Sn,它们的对应长度分别为1 2 3...n.

    对这n个木条进行排序,结果无非有下面n类: 以S1开头,以S2开头…以Sn开头。按照题目要求对这n类进行排序。

    S1 。。。

    S2 。。。

    。。。

    Sn 。。。

    如果能算出每个区间有多少种排列,那么就能确定要求的第m个排列了。好抽象呀,还是举个例子吧。如果以S1开头的有10种排列,以S2开头的有10种排列…现在有n个木条,如果要确定第15个排列,那么就可以知道第15个排列必然是以S2开头的。因为已经知道了最终排列的第一个木条是S2,那么只要依次求出后面n-1个木条即可。如果能把S2开头的区间再划分成若干个区间,并且知道每个区间的大小就和上面的问题一样了。

    S2 S1 。。。

    S2 S3 。。。

    。。。

    S2 Sn 。。。

    这时问题就转换为:有n-1个木条,现在要确定第5个排列(15-10=5,以S1开头的排列已占去了10个)

    现在结合题目,题目要求出现波浪形,即有高度变换。这时以Si开头的排列又可以分成两类:第二个木条比Si高,我们记做Hi, 第二个木条比Si低,我们记做Li。这时区间细分成如下形式:

    L1 。。。

    H1 。。。

    L2 。。。

    H2 。。。

    。。。。。。

    Ln 。。。

    Hn 。。。

    要确定最终的排列,关键是要知道每个区间里排列的个数。

    设L( x,n )表示n个木条的排列中,以长度为x的木条开始,且下一个木条比X低的排列数。H( x,n )表示n个木条的排列中,以长度为x的木条开始,且下一个比X高的的排列数

    状态转换方程:

    L( x, n ) = , 其中 1 <= i < x

    H( y, n ) = , 其中 y <= i < n

    有状态方程在手,就可以依次确定要求排列的每个木条。

    参考资料:

    http://jay23jack.blog.163.com/blog/static/317951942009130215813/

    http://blog.163.com/leyni@126/blog/static/16223010220103150173663/

     

    POJ1160

    1. #include <iostream>  
    2. using namespace std;  
    3.   
    4. //***********************常量定义*****************************  
    5.   
    6. const int V_MAX = 305;  
    7. const int P_MAX = 35;  
    8. const int INF = 999999999;  
    9.   
    10.   
    11. //*********************自定义数据结构*************************  
    12.   
    13.   
    14.   
    15.   
    16. //********************题目描述中的变量************************  
    17.   
    18. //村庄数  
    19. int vNum;  
    20. //邮局数  
    21. int pNum;  
    22. //村庄坐标  
    23. int vPos[V_MAX];  
    24.   
    25.   
    26. //**********************算法中的变量**************************  
    27.   
    28. //d[i][j]表示在村庄i和村庄j之间建1个Post office的最小距离和  
    29. int d[V_MAX][V_MAX];  
    30. //dp[i][j]表示在村庄1和村庄i之间建j个Post office的最小距离和  
    31. int dp[V_MAX][P_MAX];  
    32.   
    33.   
    34. //***********************算法实现*****************************  
    35.   
    36. void Solve()  
    37. {     
    38.     int i, j, k;  
    39.   
    40.     //利用DP,计算d[i][j]的值  
    41.     for( i=1; i<=vNum; i++ )  
    42.     {  
    43.         for( j=i+1; j<=vNum; j++ )  
    44.         {  
    45.             d[i][j] = d[i][j-1] + ( vPos[j] - vPos[( i + j )/2] );  
    46.         }  
    47.     }  
    48.   
    49.     for( i=1; i<=vNum; i++ )  
    50.     {  
    51.         dp[i][0] = INF;       
    52.     }  
    53.   
    54.     //利用DP,计算dp[i][j]的值  
    55.     for( i=1; i<=vNum; i++ )  
    56.     {  
    57.         for( j=1; j<=pNum && j<=i; j++ )  
    58.         {  
    59.             int min = INF;  
    60.             for( k=j-1; k<i; k++ )  
    61.             {  
    62.                 if( dp[k][j-1] + d[k+1][i] < min )  
    63.                     min = dp[k][j-1] + d[k+1][i];  
    64.             }  
    65.             dp[i][j] = min;  
    66.         }  
    67.     }  
    68.     cout << dp[vNum][pNum] << endl;  
    69. }  
    70.   
    71.   
    72. //************************main函数****************************  
    73.   
    74. int main()  
    75. {  
    76.     //freopen( "in.txt", "r", stdin );        
    77.       
    78.     cin >> vNum >> pNum;  
    79.     forint i=1; i<=vNum; i++ )  
    80.     {  
    81.         cin >> vPos[i];  
    82.     }  
    83.   
    84.     Solve();  
    85.     return 0;  
    86. }  


    POJ1037

    1. #include <iostream>  
    2. using namespace std;  
    3.   
    4. //***********************常量定义*****************************  
    5.   
    6. const int MAX_N = 25;   
    7.   
    8.   
    9. //*********************自定义数据结构*************************  
    10.   
    11.   
    12.   
    13.   
    14. //********************题目描述中的变量************************  
    15.   
    16. //木条的数目  
    17. int n;  
    18. //栅栏的编号  
    19. long long c;  
    20.   
    21.   
    22. //**********************算法中的变量**************************  
    23.   
    24. //up[n][i]表示:n个木条,且第一个木条长度为i的上升型栅栏数目  
    25. long long up[MAX_N][MAX_N];  
    26. //down[n][i]表示:n个木条,且第一个木条长度为i的下降型栅栏数目  
    27. long long down[MAX_N][MAX_N];  
    28.   
    29. bool used[MAX_N];  
    30. bool isPrint;  
    31.   
    32.   
    33. //***********************算法实现*****************************  
    34.   
    35. void FillTable()  
    36. {  
    37.     down[1][1] = 1;  
    38.     up[1][1] = 1;  
    39.   
    40.     down[2][1] = 0;  
    41.     up[2][1] = 1;  
    42.   
    43.     down[2][2] = 1;   
    44.     up[2][2] = 0;  
    45.       
    46.     int i, j, k;  
    47.     for( i=3; i<MAX_N; i++ )  
    48.     {  
    49.         //??? j<=MAX_N  
    50.         for( j=1; j<MAX_N; j++ )  
    51.         {  
    52.             //??? k=j  
    53.             for( k=j; k<i; k++ )  
    54.             {                 
    55.                 up[i][j] += down[i-1][k];  
    56.             }  
    57.             for( k=1; k<j; k++ )  
    58.             {  
    59.                 down[i][j] += up[i-1][k];  
    60.             }  
    61.         }  
    62.     }         
    63. }  
    64.   
    65. void SolveAndPrint( int id, int count )  
    66. {  
    67.     forint i=1; i<=count; i++ )  
    68.     {  
    69.         if( used[i] && i<=id )  
    70.         {  
    71.             id++;  
    72.             count++;  
    73.         }  
    74.     }  
    75.     used[id] = true;  
    76.   
    77.     if( isPrint )  
    78.     {  
    79.         cout << " " << id;  
    80.     }  
    81.     else  
    82.     {  
    83.         cout << id;  
    84.         isPrint = true;  
    85.     }  
    86. }  
    87.   
    88.   
    89. //************************main函数****************************  
    90.   
    91. int main()  
    92. {  
    93.     //freopen( "in.txt", "r", stdin );        
    94.   
    95.     int caseNum;  
    96.     cin >> caseNum;  
    97.       
    98.     //DP的填表  
    99.     FillTable();  
    100.   
    101.     while( caseNum-- )  
    102.     {  
    103.         cin >> n >> c;  
    104.           
    105.         //先搜索down  
    106.         bool isDown = true;  
    107.         bool isFirst = true;  
    108.         int id = 1;  
    109.         isPrint = false;  
    110.         memset( used, 0, sizeof(used) );  
    111.   
    112.         while( n )  
    113.         {  
    114.             if( isDown )  
    115.             {  
    116.                 if( c > down[n][id] )  
    117.                 {  
    118.                     c -= down[n][id++];  
    119.                       
    120.                     if( isFirst )  
    121.                     {  
    122.                         //设置标记,下次搜索up  
    123.                         isDown = false;  
    124.                         //对每个id有down和up两个值  
    125.                         //确定第一个数时,down和up都要搜索  
    126.                         id--;  
    127.                     }  
    128.                 }  
    129.                 else  
    130.                 {  
    131.                     //如果当前木条长度可确定  
    132.                     //问题规模减一  
    133.                     SolveAndPrint( id, n-- );  
    134.                     isFirst = false;  
    135.                     isDown = false;  
    136.                     id = 1;  
    137.                 }  
    138.             }  
    139.             else  
    140.             {  
    141.                 if( c > up[n][id] )  
    142.                 {  
    143.                     c -= up[n][id++];  
    144.                     if( isFirst )   isDown = true;                    
    145.                 }  
    146.                 else  
    147.                 {  
    148.                     SolveAndPrint( id, n-- );  
    149.                     isFirst = false;  
    150.                     isDown = true;  
    151.                 }  
    152.             }  
    153.         }     
    154.         cout << endl;  
    155.     }     
    156.     return 0;  
    157. }  

    版权声明:本文为博主原创文章,未经博主允许不得转载。

    today lazy . tomorrow die .
  • 相关阅读:
    逆元(费马小定理求法)
    CodeForces
    lower_bound and upper_bound
    HDU 4825 Xor Sum
    1030: [JSOI2007]文本生成器
    1070: [SCOI2007]修车
    agc 027 B
    P2664 树上游戏
    CF 314 E. Sereja and Squares
    4237: 稻草人
  • 原文地址:https://www.cnblogs.com/france/p/4808757.html
Copyright © 2011-2022 走看看