用户提了一个让人头疼的需求,麻烦帮忙看看能不能实现,谢谢!

ring2004 2011-08-29 07:53:48
假设有15个数,(上限是不定的)
用户以类似PPT输入页码打印的方式输入(大家如果有更好的方式,请指教):
第一次输入:1-7,6,9,10-12
第二次输入:5-8,14-15
第三次输入:13,14

要求同一次输入,不能重复。
(例如第一次输入时,6已经包含在1-7中)

要求每一次输入的序列与之前所有输入的序列不能有重复,不能有交集。
(例如第二次输入5-8与1-7之间有交集,第三次输入14与第二次14-15重复了)



想过让用户一个数一个数去输入,但是因为上限不定,有时需要输入很多数,所以肯定不现实。
特此求助,万分感谢!
...全文
224 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2011-08-29
  • 打赏
  • 举报
回复
仅供参考
//实现一个函数:求数轴上多个线段覆盖的区域对应的多个线段; 输入多个线段,求出被这些线段覆盖的所有区域(也用线段表示); 一条线段用两个值表示(x0,x1), 其中x1>x0;
//比如(1,3);(2,4);(5,6);结果为(1,4);(5,6);
//比如(1,3);(2,4);(5,6);(4,7);结果为(1,7);
#include <stdio.h>
#define MAXLINES 100
struct LINE {
int x0;//左端
int x1;//右端
} ls[MAXLINES];
int i,j,k,n,x0,x1,c;
void add() {
if (0==n) {//加入第一对点
ls[n].x0=x0;
ls[n].x1=x1;
n=1;
} else {
if (x1==ls[0].x0) {//右端=第一条线段的左端
ls[0].x0=x0;//第一条线段的左端修改为左端
return;
}
if (x1<ls[0].x0) {//右端<第一条线段的左端
for (i=n-1;i>=0;i--) {//将所有线段往后移
ls[i+1].x0=ls[i].x0;
ls[i+1].x1=ls[i].x1;
}
ls[0].x0=x0;//新第一条线段为x0,x1
ls[0].x1=x1;
n++;
return;
}
if (ls[n-1].x1<x0) {//左端>最后那条线段的右端
ls[n].x0=x0;//新最后那条线段
ls[n].x1=x1;
n++;
return;
}
if (x0<=ls[0].x0 && ls[n-1].x1<=x1) {//左端≤第一条线段的左端且最后那条线段的右端≤右端
ls[0].x0=x0;//只剩这一条线段
ls[0].x1=x1;
n=1;
return;
}
for (i=0;i<n;i++) {//从左到右依次检查每条线段
if (ls[i].x0<=x0 && x0<=ls[i].x1) {//第i条线段的左端≤左端≤第i条线段的右端
for (j=i;j<n;j++) {//从第i条线段开始从左到右依次检查每条线段
if (ls[j].x0<=x1 && x1<=ls[j].x1) {//第j条线段的左端≤右端≤第j条线段的右端
ls[i].x1=ls[j].x1;//第i条线段的右端改为第j条线段的右端
for (k=1;k<=n-j-1;k++) {//将剩余线段往前移
ls[i+k].x0=ls[j+k].x0;
ls[i+k].x1=ls[j+k].x1;
}
n-=j-i;
return;
}
if (ls[j].x1<x1 && (j==n-1 || x1<ls[j+1].x0)) {//第j条线段的右端<右端<第j+1条线段的左端(如果有)
ls[i].x1=x1;//第i条线段的右端改为右端
for (k=1;k<=n-j-1;k++) {//将剩余线段往前移
ls[i+k].x0=ls[j+k].x0;
ls[i+k].x1=ls[j+k].x1;
}
n-=j-i;
return;
}
}
}
if (ls[i].x1<x0 && (i==n-1 || x0<ls[i+1].x0)) {//第i条线段的右端<左端<第i+1条线段的左端(如果有)
if (i!=n-1 && x1<ls[i+1].x0) {//右端<第i+1条线段的左端(如果有)
for (k=n-1;k>=i+1;k--) {//将从第i+1条线段开始的所有线段往后移
ls[k+1].x0=ls[k].x0;
ls[k+1].x1=ls[k].x1;
}
ls[i+1].x0=x0;//新第i+1条线段为x0,x1
ls[i+1].x1=x1;
n++;
return;
}
for (j=i+1;j<n;j++) {//从第i+1条线段开始从左到右依次检查每条线段
if (ls[j].x0<=x1 && x1<=ls[j].x1) {//第j条线段的左端≤右端≤第j条线段的右端
ls[i+1].x0=x0;//第i+1条线段的左端改为左端
ls[i+1].x1=ls[j].x1;//第i+1条线段的右端改为第j条线段的右端
for (k=1;k<=n-j-1;k++) {//将剩余线段往前移
ls[i+1+k].x0=ls[j+k].x0;
ls[i+1+k].x1=ls[j+k].x1;
}
n-=j-i-1;
return;
}
if (ls[j].x1<x1 && (j==n-1 || x1<ls[j+1].x0)) {//第j条线段的右端<右端<第j+1条线段的左端(如果有)
ls[i+1].x0=x0;//第i+1条线段的左端改为左端
ls[i+1].x1=x1;//第i+1条线段的右端改为右端
for (k=1;k<n-j-1;k++) {//将剩余线段往前移
ls[i+k].x0=ls[j+k].x0;
ls[i+k].x1=ls[j+k].x1;
}
n-=j-i-1;
return;
}
}
}
if (x0<ls[i].x0) {//左端<第i条线段的左端
for (j=i;j<n;j++) {//从第i条线段开始从左到右依次检查每条线段
if (ls[j].x0<=x1 && x1<=ls[j].x1) {//第j条线段的左端≤右端≤第j条线段的右端
ls[i].x0=x0;//第i条线段的左端改为左端
ls[i].x1=ls[j].x1;//第i条线段的右端改为第j条线段的右端
for (k=1;k<=n-j-1;k++) {//将剩余线段往前移
ls[i+k].x0=ls[j+k].x0;
ls[i+k].x1=ls[j+k].x1;
}
n-=j-i;
return;
}
if (ls[j].x1<x1 && (j==n-1 || x1<ls[j+1].x0)) {//第j条线段的右端<右端<第j+1条线段的左端(如果有)
ls[i].x0=x0;//第i条线段的左端改为左端
ls[i].x1=x1;//第i条线段的右端改为右端
for (k=1;k<=n-j-1;k++) {//将剩余线段往前移
ls[i+k].x0=ls[j+k].x0;
ls[i+k].x1=ls[j+k].x1;
}
n-=j-i;
return;
}
}
}
}
}
}
void show() {
for (i=0;i<n;i++) {
printf("(%d,%d);",ls[i].x0,ls[i].x1);
}
printf("\n");
}
void main() {
n=0;
c=0;
while (1) {
printf("Input x0,x1(x0<x1;0,0 to exit):");
fflush(stdout);
rewind(stdin);
if (2==scanf("%d,%d",&x0,&x1)) {
if (0==x0&&0==x1) break;
if (x1>x0) {
c++;
if (c>=MAXLINES) {
printf("Up to %d!\n",MAXLINES);
break;
}
add();
show();
}
}
}
}
波导终结者 2011-08-29
  • 打赏
  • 举报
回复
不重复

1.借鉴算素数的筛法做,判断该数的标志位。

2.直接排除已输过的数,将剩下的数给用户选,这不是更人性化,而且保证不会重复?
三断笛 2011-08-29
  • 打赏
  • 举报
回复
重复就重复呗,重复的不予理会,只管取最大的区间打
lxq19851204 2011-08-29
  • 打赏
  • 举报
回复
比较简单的东西啊
咸清 2011-08-29
  • 打赏
  • 举报
回复
我一般这么办:
type一个类型
组成集合
然后写分析的代码⋯⋯
tang688 2011-08-29
  • 打赏
  • 举报
回复
不这这样的要求都解决不了,你很难应付真正的刁难你的客户的。
因为这种要求我个人认为是合理要求,因为对他程序的操作是有帮助的。
rixodx 2011-08-29
  • 打赏
  • 举报
回复
每次,15个标记,a[1]-a[15]

总的,15个标记, a[1]-a[15]
tang688 2011-08-29
  • 打赏
  • 举报
回复
哈!排序的同时就可以判断出来了。
比如用冒泡式排序的时候,就有大小的比对,相等的时候就提示有重复。
tang688 2011-08-29
  • 打赏
  • 举报
回复
这个不复杂的啊。
第一步,把1-7这样的格式用程序转换为1,2,3,4,5,6,7
第二步,根据大小排序
第三步,排序后一个循环判断,只要是邻近的二个数字相等就提示有重复。
worldy 2011-08-29
  • 打赏
  • 举报
回复
[Quote=引用楼主 ring2004 的回复:]
假设有15个数,(上限是不定的)
用户以类似PPT输入页码打印的方式输入(大家如果有更好的方式,请指教):
第一次输入:1-7,6,9,10-12
第二次输入:5-8,14-15
第三次输入:13,14

要求同一次输入,不能重复。
(例如第一次输入时,6已经包含在1-7中)

要求每一次输入的序列与之前所有输入的序列不能有重复,不能有交集。
(例如第二次输入5-8与1-7之间……
[/Quote]

使用split将输入页码转换为数组A
分析数组每个元素,获得一个最大页码
使用最大页码定义的独立的页数组B
再次扫描数组,将出现在A中的页,设置数组B
按照数组B确认的页打印

按照这个思路,你可以不要求页码没有交集的限制!
lliai 2011-08-29
  • 打赏
  • 举报
回复
可以实现。文本操作
无·法 2011-08-29
  • 打赏
  • 举报
回复
不知道是不是你要的,自己修改下吧。
Option Explicit

Dim a(1 To 15) As Boolean
'1-7,6,9,10-12
Private Sub Command1_Click()
MsgBox add("1-7")
MsgBox add("6")
MsgBox add("9")
MsgBox add("10-12")

Dim i%
For i = 1 To 15
Print i & vbTab & a(i)
Next
End Sub

Function add(strSec$) As Boolean
Dim i%, v
If InStr(strSec, "-") = 0 Then strSec = strSec & "-" & strSec
v = Split(strSec, "-")
'检测一遍是否已经使用
For i = v(0) To v(1)
If a(i) Then
Exit Function '退出函数
End If
Next

'如果执行到这里表示strSec段都没用过,那么开始设置
For i = v(0) To v(1)
a(i) = True
Next
add = True
End Function
ring2004 2011-08-29
  • 打赏
  • 举报
回复
拆开之后要怎么判断,可以具体点吗?谢谢
jhone99 2011-08-29
  • 打赏
  • 举报
回复
输入的数据用split拆开,然后判断
  • 打赏
  • 举报
回复
你要把6当作6-6看,可能容易点
ring2004 2011-08-29
  • 打赏
  • 举报
回复
标志位是指什么,能再具体说一下吗?
第二个方法挺好的,但是有可能不止15个数,假设是158个数,用户输入的随机性很强,第一次输入后,剩余的数就可能要再组成区间显示给用户进行选择,但有可能用户只需要大区间中的一个小区间,这可能还是需要他手动输入的。

[Quote=引用 14 楼 alifriend 的回复:]
不重复

1.借鉴算素数的筛法做,判断该数的标志位。

2.直接排除已输过的数,将剩下的数给用户选,这不是更人性化,而且保证不会重复?
[/Quote]
波导终结者 2011-08-29
  • 打赏
  • 举报
回复
代码行数少≠ “快”

直接取区间比较的话,参照握手问题,比较次数将呈几何增长
ring2004 2011-08-29
  • 打赏
  • 举报
回复
感谢各位好心人的回复,个人水平一般,还在努力学习中。

对于大家的回答,有些地方还是有些困惑,还在研究中。

个人感觉,没有必要把1-n全部转换为1,2,3,4,....n再做处理、

直接取得每个串的最大值和最小值进行区间比较更快些,不知道对不对。

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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