【Algothrim】求从n个数中取r个数的组合

来源:互联网 发布:程序设计导论 python 编辑:程序博客网 时间:2024/06/01 21:49


#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <iostream>using namespace std;#define MAX 21#define ALL 1100000int edge[MAX][MAX] = { 0 };int Answer = 0;int N, M;int Parent[ALL] = { 0 };int Queue[ALL] = { 0 };void Init(void){int i, j;for (i = 0; i < ALL; i++){Queue[i] = 0;Parent[i] = 0;}for (i = 0; i < MAX; i++){for (j = 0; j < MAX; j++){edge[i][j] = 0;edge[j][i] = 0;}}cin >> N >> M;Answer = N+1;for (i = 1; i <= N; i++){Parent[i] = 0;Queue[i] = i;}for (i = 0; i < M; i++){int a, b;cin >> a >> b;edge[a][b] = 1;edge[b][a] = 1;}}int checksafewithparent(int t, int c){int f = Parent[t];while (f != 0){if (edge[Queue[f]][c]){return 0;}f = Parent[f];}return 1;}void bfs(void){int top = N+1;int bottom = 1;while (top > bottom){int t = Queue[bottom];int i=0;for (i = t+1; i <= N; i++){if ((edge[t][i] == 0) && checksafewithparent(bottom, i)){Queue[top] = i;Parent[top] = bottom;top++;Answer++;}}bottom++;}}int main(void){int test_case;int T;freopen("input.txt", "r", stdin);setbuf(stdout, NULL);scanf("%d", &T);for (test_case = 1; test_case <= T; ++test_case){Init();bfs();cout << "#" << test_case << " " << Answer  << endl;}return 0; //Your program should return 0 on normal termination.}

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <iostream>using namespace std;#define MAX 21int edge[MAX][MAX] = { 0 };int Answer = 0;int Data[MAX] = {0};int N, M;void Init(void){Answer = 0;int i,j;for (i = 0; i < MAX; i++){for (j = 0; j < MAX; j++){edge[i][j] = 0;edge[j][i] = 0;}}cin >> N >> M;for (i = 1; i <= N; i++){Data[i] = i;}for (i = 0; i < M; i++){int a, b;cin >> a >> b;edge[a][b] = 1;edge[b][a] = 1;}}int CheckValid(int zh[], int l){int i,j;for (i = 0; i <l; i++){for (j = 0; j < l; j++){if (edge[zh[i]][zh[j]]){return 0;}}}return 1;}void GetAllCombination(int zh[], int start, int end, int index, int r){if (index == r){/*int i;for (i = 0; i < r; i++){cout << zh[i] << "\t";}cout << endl;*/int n = CheckValid(zh, r);//cout << "valid:" << n << endl;Answer += n;return;}if (start + (r - index) > end) return;zh[index] = Data[start];GetAllCombination(zh, start + 1, end, index + 1, r);GetAllCombination(zh, start + 1, end, index, r);}void CalCnts(void){int i;for (i = 1; i <= N; i++){int *zh = new int[i];GetAllCombination(zh, 1, N+1, 0, i);}}int main(void){int test_case;int T;freopen("input.txt", "r", stdin);setbuf(stdout, NULL);scanf("%d", &T);//T = 1;for (test_case = 1; test_case <= T; ++test_case){Init();CalCnts();cout << "#" << test_case << " " << Answer + 1 << endl;}return 0; //Your program should return 0 on normal termination.}

今天做算法题遇到一个问题,涉及到从n个数中求r个数的组合,于是搜了一下。

http://www.acmerblog.com/combinations-of-r-elements-6059.html

给一个数组arr,长度为n,找出从中取出r个数的所有组合。例如对于数组{1, 2, 3, 4} ,r = 2,则打印出:{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4} ,{3, 4}. 也就是 组合公式C(4,2) = 6个。 假设输入的元素没有重复,取出的r个数也没有重复。

使用递归是比较容易解决,类似分治法。组合数有如下的递归关系:C(n,r) = C(n-1, r-1) + C(n-1, r)


上面2个代码,是用来求解n个数字中,m组不能共存,求所有可以共存的种类

代码一: 用上面提到的算法求出所有的组合,然后每个组合遍历一遍,将符合条件的自增

代码二:用BFS,首先全没有是1中,每个数字单独是一种,所以算法开始前Answer就是N+1, 然后用BFS来走,所有可以加到队列里的值都是一种答案

可以用树来理解,根节点是0,第一层是1~N, 再下一层就是与父节点可以共存的点,当决定下一个节点可否入队列时,要遍历从根节点到下面的每一个父节点

这里要注意的是,用来记录父节点的不能是父节点的值,而应该是父节点在队列中的位置,才能唯一标示,不然走着走着就走错了。










阅读全文
0 0
原创粉丝点击