其他排列组合问题

目录

HDU - 1027 Ignatius and the Princess II(全排列)

HDU - 1220 Cube

POJ - 1832 连环锁(九连环的推广)


HDU - 1027 Ignatius and the Princess II(全排列)

题目:


Description

Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, "I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too." Ignatius says confidently, "OK, at last, I will save the Princess." 

"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......" 
Can you help Ignatius to solve this problem? 
Input

The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub's demand. The input is terminated by the end of file. 
Output

For each test case, you only have to output the sequence satisfied the BEelzebub's demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number. 
Sample Input

6 4
11 8
Sample Output

1 2 3 5 6 4
1 2 3 4 5 6 7 9 8 11 10

解法一:根据阶乘来计算

因为m<=10000<8!,所以当n>8时,前n-8个数一定是1,2,3,4......n-8

代码:

#include
using namespace std;

int fac[8] = { 1, 1, 2, 6, 24, 120, 720, 5040 };
int l[9];

void g(int n, int m,int dn)	//n is from 1 to 8
{
	int flag = (m - 1) / fac[n - 1] + 1;
	cout << l[flag]+dn;
	for (int i = flag; i<8; i++)l[i] = l[i + 1];
	if (n>1)
	{
		cout << " ";
		g(n - 1, m - (flag - 1)*fac[n - 1], dn);
	}
	else cout << endl;
}

void f(int n, int m)
{
	if (n > 8)
	{
		for (int i = 1; i <= n - 8; i++)cout << i << " ";
		g(8, m,n-8);
		return;
	}
	g(n, m, 0);
}

int main()
{
	int n, m;
	while (cin >> n >> m)
	{
		for (int i = 0; i < 9; i++)l[i] = i;
		f(n, m);
	}
	return 0;
}

解法二:利用STL

STL中的next_permutation函数可以直接将数组调整到下一顺序的状态。

函数的2个参数,用法和sort里面一样。

比如,对于长为n的数组l,sort(l,l+n)是排序整个数组,next_permutation是给出整个数组的下一顺序的状态。

代码:
 

#include
#include
using namespace std;

int main()
{
	int n, m,l[1001];
	while (cin >> n >> m)
	{
		for (int i = 0; i <= n; i++)l[i] = i;
		while (--m)next_permutation(l, l + n+1);
		for (int i = 1; i <= n; i++)cout << l[i] << ((i < n) ? " " : "\n");
	}
	return 0;
}

HDU - 1220 Cube

题目:


Description

Cowl is good at solving math problems. One day a friend asked him such a question: You are given a cube whose edge length is N, it is cut by the planes that was paralleled to its side planes into N * N * N unit cubes. Two unit cubes may have no common points or two common points or four common points. Your job is to calculate how many pairs of unit cubes that have no more than two common points. 

Process to the end of file. 
Input

There will be many test cases. Each test case will only give the edge length N of a cube in one line. N is a positive integer(1<=N<=30). 
Output

For each test case, you should output the number of pairs that was described above in one line. 
Sample Input

1
2
3
Sample Output

0
16
297

这个很容易推导,只要用所有的二元组C(n^3,3),去掉不满足条件的3*n*n*(n-1)即可得到答案

代码:

#include
using namespace std;

int main()
{
	int n, a;
	while (cin >> n)
	{
		a = n*n*(n + 1) + n - 6;
		cout << n*n*(n - 1)*a / 2 << endl;
	}
	return 0;
}

POJ - 1832 连环锁(九连环的推广)

题目:

许多人一定很熟悉九连环(如下图),九个环被串在一起,操作规则如下:第一个(右边)环可以任意装卸,如果第k个环没有被卸掉,而第k个环前边(右边)的所有环都被卸掉,则第k+1个环(第k个环左边的环)可以任意装卸(如果存在的话)。 
用0表示此换被卸掉,1表示此环没有被卸掉,则九连环的每个状态可以用一个长度为9的二进制串来表示,如:111111001经过一次操作可以变成111111000,也可以变成111111011,111111111经过一次操作可以变成111111110,也可以变成111111101。 
其他排列组合问题_第1张图片

任务描述: 
你现在要操作的是一个n连环,n为正整数,给出n连环的两种状态,计算出从第一种状态变换到第二种状态所需要的最少步数。 
Input
第一行是一个正整数m,表示有m组测试数据。 
每组测试数据一共3行,第一行是一个正整数n (0 < n < 128),后两行每一行描述一种状态,n个数(0或1),用空格隔开。 
Output
对于每一组测试数据输出一行,一个非负整数,表示从第一种状态变换到第二种状态所需要的最少步数。
Sample Input
2
3
0 0 0
1 0 0
4
1 0 0 0
0 1 1 0
Sample Output
7
11

递推式并不难找,如果把状态看成1个二进制数,比如1000就是8,0110就是6,记为状态8、状态6
假设从状态n转移到转态0需要的最少步数为f(n),那么f(n*2)=f(n)*2+f(n)%2,f(n*2+1)=f(n)*2+1-f(n)%2

这样,只需要从左往右扫描就可以得出该状态的f()值,把2个状态的f()值相减即为2个转态之间转移的最少步数,这一点,可以从f()的定义(最小性)推导出来

代码:
 

import java.util.*;
import java.math.BigInteger;
public class Main 
{
	public static void main(String[] args) 
	{
	    Scanner cin = new Scanner(System.in);
		int m=Integer.parseInt(cin.next());
		while (m-->0)
		{
			int n=Integer.parseInt(cin.next());
			BigInteger a=new BigInteger("0"),b=new BigInteger("0");
			for(int i=0;i

 

 

你可能感兴趣的:(其他排列组合问题)