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/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接,否则保留追究法律责任的权利。

  • 相关阅读:
    Codeforces 834D The Bakery
    hdu 1394 Minimum Inversion Number
    Codeforces 837E Vasya's Function
    Codeforces 837D Round Subset
    Codeforces 825E Minimal Labels
    Codeforces 437D The Child and Zoo
    Codeforces 822D My pretty girl Noora
    Codeforces 799D Field expansion
    Codeforces 438D The Child and Sequence
    Codeforces Round #427 (Div. 2) Problem D Palindromic characteristics (Codeforces 835D)
  • 原文地址:https://www.cnblogs.com/hsuppr/p/3086167.html
Copyright © 2011-2022 走看看