一个算法问题

volkia 2004-12-04 12:45:46
给定一个数字字符串(长度为N位),如819(长为三位),现给K个乘号,比如一个*

试问,在不改变数字字符串的顺序前提下,这些乘号放在哪些地方,得到的积最大.

如 819,一个 *, 则结果应为:
8*19 =152
81*9 =729
所以,结果为 81*9=729

现在假设N不超过40,K不超过10,请给出该算法.
...全文
356 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
volkia 2005-01-06
  • 打赏
  • 举报
回复
有几天没来了哈,我也正在找高人求解,不知会不会有结果.
findingnimo 2004-12-27
  • 打赏
  • 举报
回复
呵呵,本来我想证明你的算法是对的,可到最后竟然找了一个反例出来,应该是我对不起吧:)
你试着把它表示成数学公式,然后对这个公式求最大值。
volkia 2004-12-25
  • 打赏
  • 举报
回复
to findingnimo():

对不起,看来算法真的是有点问题!

不过,难道真的非暴力不可吗?

递归效率也不太高,还有没有其它办法?我可以重新开贴再给分哈.
findingnimo 2004-12-23
  • 打赏
  • 举报
回复
最大值: 555*555*555 = 170953875
你算得结果:5555*55*555 = 169566375
findingnimo 2004-12-23
  • 打赏
  • 举报
回复
你这个算法思想有一点问题,没有办法证明你的算法的正确性。

你试一下:
数字串:555555555 乘号个数:2
volkia 2004-12-22
  • 打赏
  • 举报
回复
import java.io.*;
public class MkMethod
{
private static double maxValue;
private static String str;
private static int multiNum;
private static ComputeNode cn;
private static int nodeNum;

MkMethod(String s,int m)
{
str=s;
multiNum=m;
maxValue=0.0;
nodeNum=1;
//cn是头结点,其字符串无用,"10"是个任意串
cn=new ComputeNode("10");
//第一个结点是串s
cn.setNext(new ComputeNode(s));
}
//返回拆分结点(字符串)p得到的整个乘积
public double getSpecMax(ComputeNode p)
{
double max=1.0;
ComputeNode next=this.cn.getNext();
for (int i=1;i<=nodeNum;i++)
{
if (next==null) break;

if (next!=p)
{
//如果不是结点p,则乘积为原串的值
max=max*next.getValue();
}
else
{
//如果是结点p,则乘积项为该串拆分后的乘积
max=max*next.getMax();
}
next=next.getNext();
}
return max;
}
//主要方法,计算每个乘号的位置和此时乘积的值
public void findMaxMultiValue()
{
ComputeNode next,current;

//一共有multiNum个乘号
for (int i=1;i<=multiNum;i++)
{
next=this.cn.getNext();
double max=0.0;
//计算每个结点的拆分结果
for (int j=1;j<=nodeNum;j++)
{
if (next==null) break;
//该结点是新结点(左子串为空,且长度不为1,且最大值不为0),则拆分
if (next.getLeftStr()==null && next.getString().length()>1 && next.getMax()<0.1)
{
next.splitStr();
}
next=next.getNext();
}
//next作为循环计算各结点最大值而设
//current指向要拆分结点的前驱结点
next=this.cn;
current=next;
maxValue=0.0;
for (int j=1;j<=nodeNum && next.getNext()!=null;j++)
{
//如果该串只有一位数字,则跳过该结点
if (next.getNext().getLeftStr()==null)
{
next=next.getNext();
continue;
}
//计算该结点拆分后的最大乘积
max=getSpecMax(next.getNext());
//如果比前一结点的最大乘积大
if (max>maxValue)
{
maxValue=max;
current=next;
}
next=next.getNext();
}
//current已指向当前应拆分结点的前驱结点
//取得其第一子串和第二子串分别构建两个新的结点left和right
ComputeNode left=new ComputeNode(current.getNext().getLeftStr());
ComputeNode right=new ComputeNode(current.getNext().getRightStr());
//将right接在left后面,并把left接到current后面
//即,使用left和right替换原来的结点
left.setNext(right);
right.setNext(current.getNext().getNext());
current.setNext(left);
//结点数加1
nodeNum++;
}
}

//将整个字符串结点输出
public String toString()
{
ComputeNode c=cn.getNext();
String s="";
for (int i=0;i<nodeNum && c!=null;i++)
{
if (i==0)
s+=c.getString();
else
s+="*"+c.getString();
c=c.getNext();
}
return s;
}
//返回整个乘积串的值
public double getMaxValue()
{
return maxValue;
}

public static void main(String[] args)
{
String s;
int n;
if(args.length != 2)
{
System.out.println("必须指定两个整型参数,第一个为数字字符串,第二为在其中插入乘号的个数.");
return;
}
s=args[0];
n=Integer.parseInt(args[1]);
if (n>=s.length())
{
System.out.println("乘号个数必须小于串的长度!");
return;
}
long x=System.currentTimeMillis();
MkMethod mm=new MkMethod(s,n);
mm.findMaxMultiValue();
System.out.print(mm.toString());
System.out.println(" ="+mm.getMaxValue());
long y=System.currentTimeMillis();
System.out.println("共耗时 "+(y-x)+" 微秒.");
}
}
volkia 2004-12-22
  • 打赏
  • 举报
回复
代码分开贴: (因为考虑到可读性和规范,所以可能会很长)
/**
* MkMethod.java
* (c)Copyright MKing,2004
*/

class ComputeNode
{
String str=null; //原串
//拆分后的字串,如果只有一个数字,则子串全为null
String subStr1=null,subStr2=null;

double value=0.0; //原串的值
double curMax=0.0; //拆分后的乘积

ComputeNode next; //下一结点

//用一个字符串构造一个结点
public ComputeNode(String s)
{
str=new String(s);
value=Double.parseDouble(s);
curMax=0.0;
next=null;
subStr1=null;
subStr2=null;
}
//拆分该结点的字符串为两个字符串,使乘积最大,最大乘积存在curMax中
public boolean splitStr()
{
int pos=0;
double max=0.0;

//如果字符串长1,即只有一个数字,则值为该值,并返回false
if (str.length()==1)
{
curMax=value;
return false;
}
//尝试乘号的可能位置
for (int i=1;i<str.length();i++)
{
String s1,s2;
s1=str.substring(0,i);
s2=str.substring(i);
double d1=Double.parseDouble(s1);
double d2=Double.parseDouble(s2)*d1;
if (d2>max)
{
max=d2;
pos=i;
}
}
//得到最大乘积和乘号位置,则子串可确定
curMax=max;
subStr1=str.substring(0,pos);
subStr2=str.substring(pos);
return true;
}

public String getString()
{
return str;
}

public String getLeftStr()
{
return subStr1;
}

public String getRightStr()
{
return subStr2;
}

public double getMax()
{
return curMax;
}

public double getValue()
{
return value;
}

public ComputeNode getNext()
{
return next;
}
public void setNext(ComputeNode c)
{
next=c;
}
}
volkia 2004-12-22
  • 打赏
  • 举报
回复
呵呵,谢谢大家!谢谢"大花猫"!

感觉求组合数太暴力了点 :)

我是这样算的:
比如 3345096 (长度为N) ,乘号个数为2
则,先求第一个乘号,很显然,应该有N-1种可能,求出最大的很简单
即将原串分成 33450(s1) * 96(s2)

再比较在s1中按上述方法插入一下乘号的积与96

33450 与在s2中按上述方法插入一个乘号后的积的大小,可确定第二个乘号

同理,可以确定余下乘号.
如果考虑封装一种结构(类)来实现,则每个子串中的乘号位置只需要计算一次,只有子串被拆分以后才需要重新计算乘号位置.因此时间复杂度并不会太大.

不过,有个问题,如果串的长度超出了长整数(long)表示的范围,则需要自定义数字字符串的乘积和大小比较方法,这个要难些.
cxz7531 2004-12-16
  • 打赏
  • 举报
回复
上面的有些缺点,出现了重复搜索的现象,再完善一下
public class MaxMulValue {
private static String asscat=""; //其值最大的组合方式
private static int ncount=0; //总的组合个数
public static void main(String[] args) {
String numstr="67545656975666"; //参照的数字字符串
int mulcount=8; //乘号个数
long nvalue=getMaxZuhe(numstr,mulcount);
System.out.println("---------------------");
System.out.println("参考字符串为 "+numstr+" 乘号个数为 "+mulcount);
System.out.println("一共"+ncount+"种组合 ");
System.out.println("最大值为 "+nvalue);
System.out.println("组合方式为 "+asscat);
System.out.println("---------------------");

}

public static long getMaxZuhe(String numstr ,int mulcount){
/*
参数含义
numstr 参照的数字字符串
mulcount 乘号个数

返回值 返回最大值
组合方式和总的组合个数在类成员asscat和ncount中
*/
int m=numstr.length();
int []ns=new int[m-1];
for(int j=0;j<m-1;j++){
ns[j]=(int)Math.round(Math.pow(2,j));
}
int nlim=(int)Math.round(Math.pow(2,m-1));
long nvalue=-1;
for(int i=0;i<nlim;i++){
int ntotal=0;
int []kk=new int[mulcount];
int kksign=0;
for(int k=0;k<m-1;k++){
if((i & ns[k])>0 ) {
ntotal++;
if(ntotal>mulcount) break ;
kk[kksign]=k;
kksign++;
}
}
if(ntotal==mulcount){
String s="";
long v=1;
for(int np=0;np<mulcount;np++){
if(np==0){
String t=numstr.substring(0,kk[np]+1);
s=s+t+"*";
v=v*Long.parseLong(t);
}else if(np==mulcount-1){
String t1= numstr.substring(kk[np-1]+1,kk[np]+1);
String t2=numstr.substring(kk[np]+1,numstr.length());
s=s+t1+"*"+t2;

v=v*Long.parseLong(t1)*Long.parseLong(t2);
}else{
String t=numstr.substring(kk[np-1]+1,kk[np]+1);
s=s+t+"*";
v=v*Long.parseLong(t);
}
}
if(nvalue<v) {
nvalue=v;
asscat=s;
}
ncount++;
System.out.println("第"+ncount+"种组合:"+s+"="+v);
}
}
return nvalue;
}

}
输出结果是:
.............................
第1282种组合:6*754565*6*9*7*5*6*6*6=1848261693600
第1283种组合:67*54565*6*9*7*5*6*6*6=1492466245200
第1284种组合:675*4565*6*9*7*5*6*6*6=1257940530000
第1285种组合:6754*565*6*9*7*5*6*6*6=1557847922400
第1286种组合:67545*65*6*9*7*5*6*6*6=1792347102000
第1287种组合:675456*5*6*9*7*5*6*6*6=1378740787200
---------------------
参考字符串为 67545656975666 乘号个数为 8
一共1287种组合
最大值为 2574142740000
组合方式为 6*7545*65*6*9*75*6*6*6
---------------------
wqqissc 2004-12-16
  • 打赏
  • 举报
回复
楼上那样的方法,恐怕是个指数级的复杂度了。呵呵,严格的说,这不是算法,是蛮力
cxz7531 2004-12-16
  • 打赏
  • 举报
回复
修改后的程序输出结果是:
....................
第2375种组合:67*54*5*6*5*6*9*7*5666=1162326639600
第2376种组合:6*7*54*5*6*5*6*9*75666=1390044952800
第2377种组合:675*4*5*6*5*6*9*7*5666=867407940000
第2378种组合:6*75*4*5*6*5*6*9*75666=1103210280000
第2379种组合:67*5*4*5*6*5*6*9*75666=821278764000
第2380种组合:6*7*5*4*5*6*5*6*975666=737603496000
---------------------
参考字符串为 67545656975666 乘号个数为 8
一共2380种组合
最大值为 2574142740000
组合方式为 6*7545*65*6*9*75*6*6*6
---------------------
qinliu0425 2004-12-16
  • 打赏
  • 举报
回复
这个很高深的,弄不懂
cxz7531 2004-12-16
  • 打赏
  • 举报
回复
刚才的程序忘了考虑超出Integer范围的问题,现在用Long代替Integer,就对了
/**
* Created on 2004-12-16
* HOPETECH
*
*
* ====================================================================
*
* The HOPETECH License, Version 1.0
*
* Copyright (c) 1999-2004 The HOPETECH Foundation. All rights
* reserved.
*/
/**
* @author tc jinsq
* @version Revision: 1.0 Date: 2004-12-16
*/
public class MaxMulValue {
private static String asscat=""; //其值最大的组合方式
private static int ncount=0; //总的组合个数
public static void main(String[] args) {
String numstr="67545656975666"; //参照的数字字符串
int mulcount=8; //乘号个数
long nvalue=getMaxZuhe(numstr,mulcount);
System.out.println("---------------------");
System.out.println("参考字符串为 "+numstr+" 乘号个数为 "+mulcount);
System.out.println("一共"+ncount+"种组合 ");
System.out.println("最大值为 "+nvalue);
System.out.println("组合方式为 "+asscat);
System.out.println("---------------------");

}

public static long getMaxZuhe(String numstr ,int mulcount){
/*
参数含义
numstr 参照的数字字符串
mulcount 乘号个数

返回值 返回最大值
组合方式和总的组合个数在类成员asscat和ncount中
*/
int m=numstr.length();
int []ns=new int[m-1];
for(int j=0;j<m-1;j++){
ns[j]=(int)Math.round(Math.pow(2,j));
}
int nlim=(int)Math.round(Math.pow(2,m-1));
long nvalue=-1;
for(int i=0;i<nlim;i++){
int ntotal=0;
int []kk=new int[mulcount];
int kksign=0;
for(int k=0;k<m-1;k++){
if((i & ns[k])>0 ) {
ntotal++;
if(ntotal>mulcount) break;
kk[kksign]=k;
kksign++;
if(ntotal==mulcount){
String s="";
long v=1;
for(int np=0;np<mulcount;np++){
if(np==0){
String t=numstr.substring(0,kk[np]+1);
s=s+t+"*";
v=v*Long.parseLong(t);
}else if(np==mulcount-1){
String t1= numstr.substring(kk[np-1]+1,kk[np]+1);
String t2=numstr.substring(kk[np]+1,numstr.length());
s=s+t1+"*"+t2;

v=v*Long.parseLong(t1)*Long.parseLong(t2);
}else{
String t=numstr.substring(kk[np-1]+1,kk[np]+1);
s=s+t+"*";
v=v*Long.parseLong(t);
}
}
if(nvalue<v) {
nvalue=v;
asscat=s;
}
ncount++;
System.out.println("第"+ncount+"种组合:"+s+"="+v);
}
}
}
}
return nvalue;
}

}
cxz7531 2004-12-16
  • 打赏
  • 举报
回复
输出结果如下:

..................................
第2373种组合:6754*5*6*5*6*9*7*5*666=-375792912
第2374种组合:6*754*5*6*5*6*9*7*5666=1691246752
第2375种组合:67*54*5*6*5*6*9*7*5666=-1609497616
第2376种组合:6*7*54*5*6*5*6*9*75666=-1524451104
第2377种组合:675*4*5*6*5*6*9*7*5666=-175453792
第2378种组合:6*75*4*5*6*5*6*9*75666=-596315072
第2379种组合:67*5*4*5*6*5*6*9*75666=940010464
第2380种组合:6*7*5*4*5*6*5*6*975666=-1130878912
---------------------
参考字符串为 67545656975666 乘号个数为 8
一共2380种组合
最大值为 2147166432
组合方式为 6*7*54*565*69*75*6*6*6
---------------------
cxz7531 2004-12-16
  • 打赏
  • 举报
回复
/**
* Created on 2004-12-16
* HOPETECH
*
*
* ====================================================================
*
* The HOPETECH License, Version 1.0
*
* Copyright (c) 1999-2004 The HOPETECH Foundation. All rights
* reserved.
*/
/**
* @author tc jinsq
* @version Revision: 1.0 Date: 2004-12-16
*/
public class MaxMulValue {
private static String asscat=""; //其值最大的组合方式
private static int ncount=0; //总的组合个数
public static void main(String[] args) {
String numstr="67545656975666"; //参照的数字字符串
int mulcount=8; //乘号个数
int nvalue=getMaxZuhe(numstr,mulcount);
System.out.println("---------------------");
System.out.println("一共"+ncount+"种组合 ");
System.out.println("最大值为 "+nvalue);
System.out.println("组合方式为 "+asscat);
System.out.println("---------------------");

}

public static int getMaxZuhe(String numstr ,int mulcount){
/*
参数含义
numstr 参照的数字字符串
mulcount 乘号个数

返回值 返回最大值
组合方式和总的组合个数在类成员asscat和ncount中
*/
int m=numstr.length();
int []ns=new int[m-1];
for(int j=0;j<m-1;j++){
ns[j]=(int)Math.round(Math.pow(2,j));
}
int nlim=(int)Math.round(Math.pow(2,m-1));
int nvalue=-1;
for(int i=0;i<nlim;i++){
int ntotal=0;
int []kk=new int[mulcount];
int kksign=0;
for(int k=0;k<m-1;k++){
if((i & ns[k])>0 ) {
ntotal++;
if(ntotal>mulcount) break;
kk[kksign]=k;
kksign++;
if(ntotal==mulcount){
String s="";
int v=1;
for(int np=0;np<mulcount;np++){
if(np==0){
String t=numstr.substring(0,kk[np]+1);
s=s+t+"*";
v=v*Integer.parseInt(t);
}else if(np==mulcount-1){
String t1= numstr.substring(kk[np-1]+1,kk[np]+1);
String t2=numstr.substring(kk[np]+1,numstr.length());
s=s+t1+"*"+t2;
v=v*Integer.parseInt(t1)*Integer.parseInt(t2);
}else{
String t=numstr.substring(kk[np-1]+1,kk[np]+1);
s=s+t+"*";
v=v*Integer.parseInt(t);
}
}
if(nvalue<v) {
nvalue=v;
asscat=s;
}
ncount++;
System.out.println("第"+ncount+"种组合:"+s+"="+v);
}
}
}
}
return nvalue;
}

}
EverythingMaster 2004-12-16
  • 打赏
  • 举报
回复
呵呵等着看大花猫的答案了!
cxz7531 2004-12-16
  • 打赏
  • 举报
回复
这是一个排列组合的问题。让我来解决。晚上给你答案
ggokind 2004-12-12
  • 打赏
  • 举报
回复
不好意思,我的方法不可行,太天真了
ggokind 2004-12-12
  • 打赏
  • 举报
回复
我觉得递归完全可以解决:
假设前K-1个*已经按要求插入,现在要插入第K个*。
在被K-1个*所分隔的数字中找到一个最大的数,从中分开就可以了(奇数位的话可以比较一下从中分开两种情况的大小)。

大家共同探讨:)。

volkia 2004-12-12
  • 打赏
  • 举报
回复
先看看,谢谢.
加载更多回复(13)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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