主题:第30次编程比赛第2题
太没劲了 [专家分:2050] 发布于 2006-06-09 12:09:00
一系列整数 (a[1],a[2],a[3], ..., a[n]),如果 a[2]-a[1] = a[3]-a[2] = ... = a[n]-a[n-1],称它们是等差数列,现在给你一个整数数列,你需要替换其中的一些数使整个成为等差数列,但是每替换一个数需要付出相关代价 1,返回使整个数列成为等差数列的最小花费代价,如果所给的数列已经是等差数列返回 0。
比赛题目:
编写函数接口:
int howmany(int *a,int num)
其中 a 表示输入数列,其中任意的输入数列成员 a[k] 有 -10000<=a[k]<=10000,num 表示对应数列中成员总个数,3<= num <=50。
函数返回最小花费代价。
注意:
A、数列成员不允许被替换成小数(即最终必须是整数等差数列)。
B、可以修改数列 a 中成员值。(可以破坏原始输入)
C、任意替换后的成员 a[k] 可以是 a[k]<-10000 或者 a[k]>10000。(替换后值可以不遵守原始输入约束)
例子:
输入 a:{1,4,7,11}
num:4
返回:1
输入 a:{-10,-5,0,5,10,15}
num:6
返回:0
输入 a:{157, 119, 15, -5, -25}
num:5
返回:2
输入 a:{1,2,4,7,11,16,22,29,37,46,56,67,79,92,106}
num:15
返回:13
输入 a:{1,100,10,40,2,200,-71,250,99,103,325}
num:11
返回:7
回复列表 (共20个回复)
11 楼
ybf1209 [专家分:120] 发布于 2006-06-10 12:12:00
#include<iostream.h>
int howmany(int *a,int num)
{
int e=0,x;
a=new int [num];
int *b=new int [num-1];
int *c=new int [num-1];
cout<<"输入数组元素:" ;
for(int r=0;r<num;r++)cin>>a[r];
for(int t=0;t<num-1;t++)c[t]=0;
for(int i=0;i<num-1;i++)b[i]=a[i+1]-a[i];
for(int j=0;j<num-2;j++)
if(b[j]==b[j+1])e++;
if(e==num-1)x=0;
for(int p=0;p<num-1;p++)
for(int q=p;q<num-1;q++)if(b[p]==b[q])c[p]++;
int d=c[0];
for(int s=1;s<num-2;s++)if(d<c[s+1])d=c[s+1];
s=num-d-1;
return s;
}
void main()
{
int num,s=0;
cout<<"输入数组的数目:";
cin >>num;
int *a=new int [num];
s=howmany(a,num);
cout<<"input"<<endl;
cout<<s<<endl;
}
12 楼
天边蓝 [专家分:1810] 发布于 2006-06-10 23:40:00
#include<iostream>
#include<string>
using namespace std;
struct data{
int sub;
int i;
int j;
};
int howmany(int *p,int num){
data *q=new data[num];
int *ch=new int[num];
int max=0;
memset(ch,0,num*4);
int inc=0;
for(int i=0;i<num;i++){
for(int j=0;j<num;j++){
if(j==i){
q[j].sub=20001;
continue;
}
if((p[i]-p[j])%(i-j)==0)
q[j].sub=i>j?(p[i]-p[j])/(i-j):(p[j]-p[i])/(j-i);
else
q[j].sub=20001;
q[j].i=i;
q[j].j=j;
}
for(int mi=0;mi<num-1;mi++){
if((q+mi)->sub==20001)
continue;
for(int j=0;j<num;j++){
if((q+j)->sub!=20001&& (q+j)->sub==(q+mi)->sub)
ch[(q+j)->i]=ch[(q+j)->j]=1;
}
for(int k=0,count=0;k<num;k++){
if(ch[k]==1)
count++;
}
max=(count>max)?count:max;
memset(ch,0,num*4);
}
memset(q,0,num*12);
}
return num-max;
}
13 楼
eastcowboy [专家分:25370] 发布于 2006-06-11 02:49:00
#include <stdio.h>
#define Max 50
int howmany(int *a, int num)
{
int max = 0;
int gap;
for(gap=num-1; gap>0; --gap)
{
int start;
for(start=0; start<num; ++start)
{
int count = 1;
int p;
int x = a[start+gap] - a[start];
if( x % gap != 0 )
continue;
x /= gap; /* 目前等差数列的差为x */
for(p=start+1; p<num; ++p)
{
if( a[p]-a[start] == x*(p-start) )
++count;
}
if( count > max )
max = count;
}
}
return num - max;
}
int main()
{
int a1[] = {1,4,7,11},
a2[] = {-10,-5,0,5,10,15},
a3[] = {157, 119, 15, -5, -25},
a4[] = {1,2,4,7,11,16,22,29,37,46,56,67,79,92,106},
a5[] = {1,100,10,40,2,200,-71,250,99,103,325};
printf("%d\n", howmany(a1, 4));
printf("%d\n", howmany(a2, 6));
printf("%d\n", howmany(a3, 5));
printf("%d\n", howmany(a4, 15));
printf("%d\n", howmany(a5, 11));
return 0;
}
14 楼
goal00001111 [专家分:4030] 发布于 2006-06-11 19:39:00
#include<iostream>
using namespace std;
typedef struct bnode //有序二叉树btree
{
int data;
struct bnode *lchild, *rchild;
} btree;
void Distroy(btree *b)//销毁有序二叉树b
{
if (b)
{
Distroy(b->lchild);
Distroy(b->rchild);
delete b;
}
}
btree* insert(btree *b, int x)//把x插入有序二叉树b
{
if(b == NULL)
{
b = new btree;
if(b == NULL)
{
puts("wrong");
exit(1);
}
b->data = x; //putchar(x);
b->lchild = b->rchild = NULL;
}
else if(b->data == x)//不做任何插入操作
;
else if(b->data > x)//把s所指结点插入到左子树中
b->lchild = insert(b->lchild, x);
else //把s所指结点插入到右子树中
b->rchild = insert(b->rchild, x);
return b;
}
btree* search(btree *b, int x)//在有序二叉树b中寻找x
{
if(b == NULL)
return NULL;
if(b->data == x)
return b;
if(b->data > x)
return search(b->lchild, x);
else
return search(b->rchild, x);
}
int howmany(int *a, int num)//主要操作函数
{
int min = num;//用来存储最小代价
btree *cd = NULL; //有序二叉树b用来存储所有可能的公差
for (int i=0; i<num-1; i++)//i表示第一个数的下标
{
for (int j=i+1; j<num; j++)//j表示第二个数的下标
{
int d = (a[j]-a[i])/(j-i);//d表示包含第一个数和第二个数的等差数列的公差
int sum = 0;//累计花费代价
//如果该d为整数且第一次出现,累计以其为公差的数列所需花费代价
if (d*(j-i) == (a[j]-a[i]) && search(cd, d) == NULL)
{
cd = insert(cd, d);
for (int k=0; k<num; k++)//遍历数组,累计花费代价
{
if (a[k] != a[i]+(k-i)*d)
sum++;
if (sum >= min)
break;
}
if (sum < min)//存储最小代价
min = sum;
}
}
}
Distroy(cd);
return min;
}
int main(void)
{
const int max = 11;
int a[max] ={1,100,10,40,2,200,-71,250,99,103,325};
int n = howmany(a, max);
cout << n << endl;
system("pause");
return 0;
}
15 楼
ckeryradish [专家分:140] 发布于 2006-06-11 20:12:00
// 最后形成的等差数列中,必然保留有至少两个原来的数列成员ai和aj (其中j>i)
// 而任意的一个数列可以由其中的两个数列成员ai和aj决定,
// 记等差数列成员为ai=a0+di,那么可以求出
// d=(aj-ai)/(j-i)
// a0=ai-d*i
// 因此,问题变为保留那两个成员才是最合适的
// 从数列a中,任意选择两个成员,这样就决定了一系列的数列new_a,
// 判断每个new_a和原来a中成员不相同的个数(实际上就是需要修改数列成员的个数),
// 记录下最小的不相同数目
// 新的数列中很有可能某些是一样的,这样子就会存在重复比较!
//#define MAX_NUM 10000
int howmany(int *a,int num)
{
if(num<=2) return 0;
#ifndef MAX_NUM
int ** arrTried =new int *[2];
if(!arrTried)
return -1;
arrTried[0] = new int[num-1];
arrTried[1] = new int[num-1];
if( !arrTried[0] || !arrTried[1])
return -1;
#else
int arrTried[2][MAX_NUM-1];
#endif
int LestChange=num-2;
// for(int i=0;i<num-1;i++)
for(int i=num-2;i>=0;i--)
{
//当所给的刚好是等差数列时
if(!LestChange)
return 0;
for(int j=i+1,nTryTimes=0;j<num;j++)
{
int temp1=a[j]-a[i];
int temp2=j-i;
if(temp1%temp2/*!=0*/)//最终必须是整数等差数列
continue;
//如果最终的数列中保留有原来的这个a[i]和a[j],则
int d=temp1/temp2;
int a0=a[i]-d*i;
//判断当前a[i]和a[j]决定的数列是否和a[i]与a[j'](j'的取值为 0<=j'<=j-1)决定的数列是一样的,
//一样的话,则表示已经比较过了。
//这样子仅仅是减少了部分的重复比较而已!
int k;
for(k=0;(a0!=arrTried[0][k] || d!=arrTried[1][k]) && k<nTryTimes;k++)
{
}
if(k!=nTryTimes)//找到重复
{
continue;
}
else
{
arrTried[0][nTryTimes]=a0;
arrTried[1][nTryTimes]=d;
nTryTimes++;
}
//比较由a0,d决定的当前数列和原来的数列之间成员不相同的个数
int Change=0;
for(int l=0,temp3=a0 ; l<num ; l++,temp3+=d)
{
if(a[l] !=temp3)
Change++;
if(Change>=LestChange) break;
}
if(Change<LestChange)//记录下最小的不相同数目
LestChange=Change;
}
}
#ifndef MAX_NUM
if(arrTried)
{
if(arrTried[0])
delete [] arrTried[0];
if(arrTried[1])
delete [] arrTried[1];
delete [] arrTried;
}
#endif
return LestChange;
}
16 楼
梅文华 [专家分:30] 发布于 2006-06-11 22:55:00
int howmany(int *a, int num)
{
int w = 0;
int d = a[1] - a[0];
int n1 = 0, n2 = 0;
for(int i = 1; i <= num - 1; i ++)
{
int dMax = a[i] - a[i - 1];
for(int j = 1; j <= num - 1; j ++)
{
if(a[j] - a[j - 1] == dMax)
n1 ++;
}
if(n1 > n2)
{
n2 = n1;
w = i - 1;
}
n1 = 0;
}
int total = 0;
d = a[w + 1] - a[w];
for(int b = w + 2; b <= num - 1; b ++)
{
if(a[b] != a[b - 1] + d)
{
a[b] = a[b - 1] + d;
total ++;
}
}
for(int c = w - 1; c >= 0; c --)
{
if(a[c] != a[c + 1] - d)
{
a[c] = a[c + 1] - d;
total ++;
}
}
return total;
}
17 楼
88882323 [专家分:0] 发布于 2006-06-12 07:25:00
顶
18 楼
sWintYeT [专家分:350] 发布于 2006-06-12 10:52:00
想看下内容,顶下
19 楼
天国龙 [专家分:490] 发布于 2006-06-12 13:05:00
void serch(int *a,int num,int p[50][50],int t,int eqs)
{
int s,i,*rp;
rp=new int[num-t-1];
s=1;
rp[0]=t;
for (i=t+1;i<num;i++)
if (((a[t]-a[i])/(i-t))==eqs)
if ((a[t]-a[i])%(i-t)==0)
rp[s++]=i;
for (i=0;i<s-1;i++)
for(int j=i+1;j<s;j++)
p[rp[i]][rp[j]]=s;
}
int howmany(int *a,int num)
{
int p[50][50],i,s,j;
for (i=0;i<num-1;i++)
{
for (j=0;j<num;j++)
p[i][j]=0;
}
for (i=0;i<num-1;i++)
for(j=i+1;j<num;j++)
if (p[i][j]==0)
if ((a[i]-a[j])%(j-i)==0)
serch(a,num,p,i,(a[i]-a[j])/(j-i));
else p[i][j]=-1;
s=p[0][1];
for (i=0;i<num-1;i++)
for(j=i+1;j<num;j++)
if (s<p[i][j])
s=p[i][j];
cout <<s<<endl;
return num-s;
}
20 楼
pigeonoo [专家分:130] 发布于 2006-06-12 13:24:00
int howmany(int *a,int num)
{
int b[50];
int c[50];
int i,j,def,t=0,cost=0;
b[0]=c[0]=1;
for (i=1;i<50;i++)
{
b[i]=0;
c[i]=-1;
}
for (i=0;i<num-1;i++)
{
b[i]=a[i+1]-a[i];
}
for(i=0;i<num;i++)
{
for (j=0;j<i;j++)
{
if (b[j]==b[i])
{
c[j]++;
c[i]=0;
break;
}
else
if(i!=0)
c[i]=1;
}
}
def=c[0];
for (i=1;i<num-1;i++)
if (c[i]>def)
{
def=c[i];
t=i;
}
for (i=t-1;i>=0;i--)
{
a[i]=a[i+1]-def;
cost++;
}
for (i=t+1;i<num;i++)
{
if (a[i]!=(a[i-1]+def))
{
a[i]=a[i-1]+def;
cost++;
}
}
return cost;
}
我来回复