请教各位一个高难的算法题,有重谢!

zzq_xaut 2008-01-20 08:03:30
请教各位一个高难的算法题:
例如有3行4列的非负整数矩阵,如下:
1 2 3 4
5 6 7 8
9 10 11 12
约束条件是:排列的结果中必须保证——1在2的前面、2在3的前面等等;5在6的前面、6在7的前面等等;9至12依次类推;而且1、5、9谁在前谁在后不受任何限制。
这样,对该矩阵进行某种特定的复杂运算后得到多个排列(可能有重复的),比如其中的一个排列如下:
1 5 2 6 9 3 10 7 11 8 12 4
现在问题是:如何对此排列实施随机性的变换,使其仍然符合上述约束条件并且和原来的排列不一样???

我的QQ 121622170,如能解决必有重谢!
...全文
455 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
zzq_xaut 2008-02-23
  • 打赏
  • 举报
回复
HW121,谢谢!貌似你的回答最接近我的要求,给你分!
ai_3621 2008-02-09
  • 打赏
  • 举报
回复
这个easy啊。

计算下总计多少个排列数字,编号,

假设总数为x,

随机输入一个数字,把该数字加上+一个随即数字,

把当前编号+随机数字编号的排列输出即可。


HW121 2008-01-30
  • 打赏
  • 举报
回复
使用STL中next_permutation很容易解决这个问题:
1、用一个临时排列,每行元素值等于行标;
2、将临时排列中的相同行号按每列的顺序排列即可。
实施随机性的变换,可以将临时排列调用next_permutation, prev_permutation后再步骤2,可得出下一个或上一个排列
遍历,可以从最小开始,调用next_permutation生成下一个临时,换算成符合上述约束条件,直至走遍所有的排列。
#include   <stdio.h> 
#include <algorithm>
using namespace std;

void main()
{
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
int row[12], count = 0;
for(int r = 0; r < 3; r++)
for(int i = 0; i < 4; i++)
row[r*4+i] = r;
do {
int i, b[3];
for(i = b[0] = b[1] = b[2] = 0; i < 12; i++)
printf("%2d ", a[ row[i] ][ b[row[i]]++ ] );
printf("\n");
count++;
}while( next_permutation(row, row + 12) );
printf("count=%d\n",count);
}
zzq_xaut 2008-01-23
  • 打赏
  • 举报
回复
chinaunix上有人这么说:
其实可以建立一个偏序集。那种在这个偏序集中无法比较大小的元素,或者不在这个偏序集上的元素可以互相交换,不影响对规则的遵守。
规则,1在2之前,1在3之前
1 大
/ \
2 3 小
2和3可以互相交换



如果偏序集上的元素小于等于10个,那么选择任意两个不在偏序集上的元素交换即可。
否则的话,只要偏序集不是链,那么在任何一个分叉点,取该分叉点的两个最小上界或者最小下界,让其交换即可。

另外,如果该偏序集的图并非连通图的话,在不同的连通子图上取点,交换也可。

<introduction of algorithms>第22章里<topological sort>描述的就是这种问题.

将那些有先后关系的结点按父子关系排成一棵树, 最后的问题就成了树或森林的遍历。
liuzongqiang 2008-01-23
  • 打赏
  • 举报
回复
明白其中难点了,一会就帮你弄出来.
liuzongqiang 2008-01-23
  • 打赏
  • 举报
回复
随机性的变换什么意思啊?
我原来给你的代码稍微修改一下你想怎么变就怎么变
jmulxg 2008-01-22
  • 打赏
  • 举报
回复
原序列1,5,2,6,9,3,10,7,11,8,12,4

1、随机产生位置种子(0-11),比如位置3,则选择数字'6'

2、'6'属于第二组(闭区间[5,8]),因此随机左右移动'6',满足'6'的位置在'5','7'之间即可;若随机到数字'1','5','9','4','8','12'需要特殊的处理,
比如'1',则可以移动的区间为 开始到'2'之前,而'4'可以移动的区间'3'之后到结束

3、重复步骤(2)N(N=1,2,3..)次即可
HW121 2008-01-22
  • 打赏
  • 举报
回复
更正:
如果要再已有的排列对几个数字实施随机性的变换,可以先找到这几个数字所在位置的连续区间,存到数组x[xn]中,
将这个区间数字按行分类A1[n1]、A2[n2]、A3[n3],
在xn个位置随机选择n1个位置, 将A1数据由小到大放入x对应位置,继续在剩下随机选择n2个位置将A2数据由小到大放入x对应位置,至结束。

最简单情况:
如果要交换一个数字c,找到数字c位置,向后移动出现非自己行数据d,从d开始与前一个位置交换,至原c的位置;这就是向后移动数字c的下一个位置。


HW121 2008-01-22
  • 打赏
  • 举报
回复
我看这是一个排列组合问题,给一个遍历的方法:
1、在12个位置选择四个位置有C(4,12)种组合,将第一行数据由小到大放入四个位置。
2、在剩下的8个位置中选择四个位置,将第二行数据由小到大放入四个位置。
3、在剩下的四个位置,将第第三行数据由小到大放入四个位置。
总共有C(4,12)×C(4,8)×C(4,4) = 34965可能

如果要再已有的排列对几个数字实施随机性的变换,可以先找到这几个数字所在位置,存到数组x[xn]中,
这些数字按行分类A1[n1]、A2[n2]、A3[n3],
在xn个位置随机选择n1个位置, 将A1数据由小到大放入x对应位置,继续在剩下随机选择n2个位置将A2数据由小到大放入x对应位置,至结束。


liuzongqiang 2008-01-22
  • 打赏
  • 举报
回复
还不给分啊.^_^
guzhilei1986 2008-01-21
  • 打赏
  • 举报
回复
期待中……
zzq_xaut 2008-01-21
  • 打赏
  • 举报
回复
liuzongqiang,非常感谢你的回复!但是问题没有解决,生成符合约束条件的排列倒是不难,而我需要解决的问题是:

如果已有一个符合约束的排列(用一维整型数组存储表示),例如:1 5 2 6 9 3 10 7 11 8 12 4,现在要求对此排列实施随机性的变换(比如随机交换2或3个数字等),使得变换出的排列既符合约束条件又和原来的不一样。
zzq_xaut 2008-01-21
  • 打赏
  • 举报
回复
非常感谢!等我测试好了就给分!!!
liuzongqiang 2008-01-20
  • 打赏
  • 举报
回复
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define COLUMN 4
#define LINE 3
void pump(int line,int column,int out[])
{
int r,t=column*line,i=t;int *a;
a=(int*)malloc(sizeof(int)*t);
while(--i>=0)
{
if(i%column==0)a[i]=0;
else a[i]=i-1;
}
i=0;/*other use*/
int j=0;
int c;
while(true)
{
if(line<1)break;
c=-1;
r=rand()%line+1;
while(r-->0)
{
c+=column;
while(a[c]==-1)c+=column;
}
c=c-column+1;
while(a[c]==-1)c++;
out[j++]=c;
a[c]=-1;
if((c+1)%column==0)line--;
else a[c]=-1;
}

}

int main()
{
srand((unsigned int)time(NULL));
int a[]={
1,2,3,4,
5,6,7,8,
9,10,11,12
};
int out[12];
pump(3,4,out);
for(int i=0;i<COLUMN*LINE;i++)
{
printf("%d ",a[out[i]]);
if(!((i+1)%COLUMN))printf("\n");
}
}

vc6编译通过.
pump实现你所要的功能,main()测试
每次执行打印随机打印一个序列.
main中数组a的元素可以随便改,但是个个数应该等于调用时column*line
有问题联系我.
liuzongqiang 2008-01-20
  • 打赏
  • 举报
回复
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void pump(int line,int column,int out[])
{
int r,t=column*line,i=t;int *a;
a=(int*)malloc(sizeof(int)*t);
while(--i>=0)
{
if(i%column==0)a[i]=0;
else a[i]=i-1;
}
i=0;/*other use*/
int j=0;
int c;
while(true)
{
if(line<1)break;
c=-1;
r=rand()%line+1;
while(r-->0)
{
c+=column;
while(a[c]==-1)c+=column;
}
c=c-column+1;
while(a[c]==-1)c++;
out[j++]=c;
a[c]=-1;
if((c+1)%column==0)line--;
else a[c]=-1;
}

}

int main()
{
srand((unsigned int)time(NULL));
int a[]={
1,2,3,4,
5,6,7,8,
9,10,11,12
};
int out[12];
pump(3,4,out);
for(int i=0;i<12;i++)
{
printf("%d ",a[out[i]]);
if(!((i+1)%4))printf("\n");
}
}



vc6编译通过.
pump实现你所要的功能,main()测试
每次执行打印随机打印一个序列.
main中数组a的元素可以随便改,但是个个数应该等于调用时column*line
有问题联系我.

33,009

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧