全排列问题 (dfs)
题目描述
按照字典序输出自然数 11 到 nn 所有不重复的排列,即 nn 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
输入格式
一个整数 nn。
输出格式
由 1 \sim n1∼n 组成的所有不重复的数字序列,每行一个序列。
每个数字保留 55 个场宽。
输入输出样例
3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
说明/提示
1<=n<=9
#include<iostream> #include<cstring>//memset函数的头文件 using namespace std; int n, st[30];//是否用过 int ans[30];//结果; void dfs(int x)//x代表下标:第一个数第二个数... { //边界条件:当到低n个数的时候; if (x > n) { for (int i = 1; i <= n; i++) printf("%5d", ans[i]); cout << endl; return; } //从一开始排列,用过的就不排; for (int i = 1; i <= n; i++) { if (st[i] == 0)//没来过 { st[i] = 1; ans[x] = i; dfs(x + 1); st[i] = 0; } } } int main() { cin >> n; memset(st, 0, sizeof(st)); dfs(1); return 0; }
问题描述
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
输入格式
从标准输入读入一个正整数N (N<1000*1000)
输出格式
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
#include<iostream> #include<cstring> using namespace std; int use[30], ans[30]; int cnt = 0; int n; //先全排列,然后在8个空中选一个插入+再选一个插入/ void dfs(int x) { if (x > 9)//全排列完之后; { for(int i=1;i<=7;i++)//下标 for (int j = i + 1; j <= 8; j++) {//将数字变成第一个十进制的数; int a = 0; for (int k = 1; k <= i; k++) { a *= 10; a += ans[k]; } //变成第二个十进制数 int b = 0; for (int k = i + 1; k <= j; k++) { b *= 10; b += ans[k]; } //第三个 int c = 0; for (int k = j + 1; k <= 9; k++) { c *= 10; c += ans[k]; } //if (b % c != 0) continue; //if (a + b / c == n) continue; if (b % c == 0 && a + b / c == n) cnt++; } //cout << cnt;不知道为什么把输出加在这里会死循环! } for (int i = 1; i < 10; i++) { if (use[i] == 0) { use[i] = 1; ans[x] = i; dfs(x + 1); use[i] = 0; } } } int main() { cin >> n; memset(use, 0, sizeof(use)); dfs(1); cout << cnt; return 0; }
八皇后问题
题目描述
任意两个皇后都不能处于同一行、同一列或同一斜线上,请问有多少种摆法。
输入
n表示皇后的个数‘,其中1<=n<=n.
输出
输出所有的情况,皇后用Q表示,其他地方用.表示
每种情况用空行隔开。
#include<iostream> #include<cstring> using namespace std; int user[30];//列; int usez[30];//正对角线; int usef[30];//副对角线; int ans[50][50];//最后的情况; int n; void dfs(int x)//列 { if (x > n) { for (int i = 1; i <= n; i++) { for (int x = 1; x <= n; x++) { if (ans[i][x] == 1) { cout << 'Q'; } else { cout << '.'; } } cout << endl; } cout << endl; return; } for (int i = 1; i <= n; i++)//行相当于横坐标;副对角线:y=x+k即y-x=k即x-i=k;同理,正对角线为x+i=k,为常数,一次代表每条对角线。 { if (user[i] == 0 && usez[x - i + 10] == 0 && usef[x + i + 10] == 0)//0没用过,+10是因为平行于副对角线的最右边的那条线,常数为负数。 { user[i] = 1; usez[x - i + 10] = 1; usef[x + i + 10] = 1; ans[i][x] = 1;//有皇后; dfs(x + 1); ans[i][x] = 0; user[i] = 0; usez[x - i + 10] = 0; usef[x + i + 10] = 0; } } } int main() { cin >> n; memset(user, 0, sizeof(user)); memset(usez, 0, sizeof(usez)); memset(usef, 0, sizeof(usef)); memset(ans, 0, sizeof(ans)); dfs(1); return 0; }
题目描述
一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:
行号 1\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6
列号 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 33 个解。最后一行是解的总个数。
输入格式
一行一个正整数 nn,表示棋盘是 n \times nn×n 大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
6
2 4 6 1 3 5 3 6 2 5 1 4 4 1 5 2 6 3 4
说明/提示
【数据范围】
对于 100\%100% 的数据,6 \le n \le 136≤n≤13。
题目翻译来自NOCOW。
USACO Training Section 1.5
//第一次做错是因为,没看到列数按字典序输出; //所以,如果先定住列,循环行的话,输出列肯定全是1,2,3,,, //如果先定住行,循环列的话,输出的列肯定就是字典序啦 //所以这个八皇后代码与上一个区别就是,dfs(参数是行数) #include<iostream> #include<cstring> using namespace std; int user[30];//列; int usez[30];//正对角线; int usef[30];//副对角线; int ans[50][50];//最后的情况; int n, cnt = 0, total = 0; void dfs(int x)//hang { if (x > n) { for (int x = 1; x <= n; x++) { for (int i = 1; i <= n; i++) { if (ans[x][i] == 1&&total<3) { cout << i << " "; } } } if (total < 3) cout << endl; cnt++; total++; return; } for (int i = 1; i <= n; i++)//i 相当于列; { if (user[i] == 0 && usez[i - x + 14] == 0 && usef[x + i + 14] == 0)//0没用过,+14是因为平行于副对角线的最右边的那条线,常数为负数。 { user[i] = 1; usez[i - x + 14] = 1; usef[x + i + 14] = 1; ans[x][i] = 1;//有皇后; dfs(x + 1); ans[x][i] = 0; user[i] = 0; usez[i - x + 14] = 0; usef[x + i + 14] = 0; } } } int main() { cin >> n; memset(user, 0, sizeof(user)); memset(usez, 0, sizeof(usez)); memset(usef, 0, sizeof(usef)); memset(ans, 0, sizeof(ans)); dfs(1); cout << cnt ; return 0; }
浙公网安备 33010602011771号