zoukankan      html  css  js  c++  java
  • poj1037, A decorative fence, ceoi2002

    解题报告见黑书p257。

    以下转自http://blog.csdn.net/sj13051180/article/details/6669737

    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/

    #include <iostream>
    
    using namespace std;
    
    //***********************常量定义*****************************
    
    const int MAX_N = 25; 
    
    
    //*********************自定义数据结构*************************
    
    
    
    
    //********************题目描述中的变量************************
    
    //木条的数目
    int n;
    //栅栏的编号
    long long c;
    
    
    //**********************算法中的变量**************************
    
    //up[n][i]表示:n个木条,且第一个木条长度为i的上升型栅栏数目
    long long up[MAX_N][MAX_N];
    //down[n][i]表示:n个木条,且第一个木条长度为i的下降型栅栏数目
    long long down[MAX_N][MAX_N];
    
    bool used[MAX_N];
    bool isPrint;
    
    
    //***********************算法实现*****************************
    
    void FillTable()
    {
    	down[1][1] = 1;
    	up[1][1] = 1;
    
    	down[2][1] = 0;
    	up[2][1] = 1;
    
    	down[2][2] = 1;	
    	up[2][2] = 0;
    	
    	int i, j, k;
    	for( i=3; i<MAX_N; i++ )
    	{
    		//??? j<=MAX_N
    		for( j=1; j<MAX_N; j++ )
    		{
    			//??? k=j
    			for( k=j; k<i; k++ )
    			{				
    				up[i][j] += down[i-1][k];
    			}
    			for( k=1; k<j; k++ )
    			{
    				down[i][j] += up[i-1][k];
    			}
    		}
    	}		
    }
    
    void SolveAndPrint( int id, int count )
    {
    	for( int i=1; i<=count; i++ )
    	{
    		if( used[i] && i<=id )
    		{
    			id++;
    			count++;
    		}
    	}
    	used[id] = true;
    
    	if( isPrint )
    	{
    		cout << " " << id;
    	}
    	else
    	{
    		cout << id;
    		isPrint = true;
    	}
    }
    
    
    //************************main函数****************************
    
    int main()
    {
    	//freopen( "in.txt", "r", stdin );		
    
    	int caseNum;
    	cin >> caseNum;
    	
    	//DP的填表
    	FillTable();
    
    	while( caseNum-- )
    	{
    		cin >> n >> c;
    		
    		//先搜索down
    		bool isDown = true;
    		bool isFirst = true;
    		int id = 1;
    		isPrint = false;
    		memset( used, 0, sizeof(used) );
    
    		while( n )
    		{
    			if( isDown )
    			{
    				if( c > down[n][id] )
    				{
    					c -= down[n][id++];
    					
    					if( isFirst )
    					{
    						//设置标记,下次搜索up
    						isDown = false;
    						//对每个id有down和up两个值
    						//确定第一个数时,down和up都要搜索
    						id--;
    					}
    				}
    				else
    				{
    					//如果当前木条长度可确定
    					//问题规模减一
    					SolveAndPrint( id, n-- );
    					isFirst = false;
    					isDown = false;
    					id = 1;
    				}
    			}
    			else
    			{
    				if( c > up[n][id] )
    				{
    					c -= up[n][id++];
    					if( isFirst )	isDown = true;					
    				}
    				else
    				{
    					SolveAndPrint( id, n-- );
    					isFirst = false;
    					isDown = true;
    				}
    			}
    		}	
    		cout << endl;
    	}	
    	return 0;
    }
    

    以上转自http://blog.csdn.net/sj13051180/article/details/6669737

    mycode:

    /**
     * Problem:POJ1037
     * Author:Shun Yao
     * Time:2013.5.18
     * Result:Accepted
     * Memo:DP
     */
    
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    
    using namespace std;
    
    class Gnode {
    public:
    	long long down, up;
    	Gnode() {
    		down = up = 0;
    	}
    	~Gnode() {}
    } g[22][22];
    char used[22], isprint;
    
    void SolveAndPrint(long id, long count) {
    	static long i;
    	for (i = 1; i <= id && i <= count; ++i)
    		if (used[i]) {
    			++id;
    			++count;
    		}
    	used[id] = 1;
    	if (isprint)
    		putchar(' ');
    	else
    		isprint = 1;
    	printf("%ld", id);
    }
    
    int main() {
    	static long i, j, k, K, n, id;
    	static long long c;
    	static char isdown, isfirst;
    	freopen("poj1037.in", "r", stdin);
    	freopen("poj1037.out", "w", stdout);
    	g[1][1].down = g[1][1].up = 1;
    	for (i = 2; i <= 20; ++i) {
    		for (j = 1; j <= i; ++j) {
    			g[i][j].down = g[i][j].up = 0;
    			for (k = 1; k < j; ++k)
    				g[i][j].down += g[i - 1][k].up;
    			for (k = j; k < i; ++k)
    				g[i][j].up += g[i - 1][k].down;
    		}
    	}
    	scanf("%ld", &K);
    	while (K--) {
    		scanf("%ld%lld", &n, &c);
    		memset(used, 0, sizeof used);
    		isprint = 0;
    		isdown = 1;
    		isfirst = 1;
    		id = 1;
    		while (n) {
    			if (isdown) {
    				if (c > g[n][id].down) {
    					c -= g[n][id].down;
    					if (isfirst)
    						isdown = 0;
    					else
    						++id;
    				} else {
    					SolveAndPrint(id, n--);
    					isfirst = 0;
    					isdown = 0;
    					id = 1;
    				}
    			} else {
    				if (c > g[n][id].up) {
    					c -= g[n][id++].up;
    					if (isfirst)
    						isdown = 1;
    				} else {
    					SolveAndPrint(id, n--);
    					isfirst = 0;
    					isdown = 1;
    				}
    			}
    		}
    		putchar('\n');
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    


    作者:HSUPPR
    出处:http://www.cnblogs.com/hsuppr/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接,否则保留追究法律责任的权利。

  • 相关阅读:
    010_STM32CubeMXADC
    009_STM32CubeMXPWM
    008_STM32CubeMX定时器中断
    007_STM32CubeMX外部中断
    006_STM32CubeMX按键输入
    005_STM32CubeMX串口
    004_STM32CubeMX官方例程
    003_STM32CubeMX点灯
    002_STM32CubeMX配置基础工程
    006_word发表博客到博客园中
  • 原文地址:https://www.cnblogs.com/hsuppr/p/3086167.html
Copyright © 2011-2022 走看看