题意:
给定一些长度,求在尺上最少标几个刻度,可以使得利用刻度差求得给定的所有长度。在满足刻度数量最少的前提下,还需保证总长度最小。
解题:
好复杂的思路,写了一遍。
n的50是个幌子,m最大为7。组合数最大为21。利用某某性质,可以用原有差值减出结果集合。数量为21*20/2。然后递增元素个数在结果集中选择元素,并计算是否能够囊括所有的给定元素,若可以,则为结果。(0和最大元素必选)
额,讲的好不清楚。
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <set>
using namespace std;
int arr[50],pro[210],cho[210],p1,p2;
bool vis[1000010],sign;
void dfs(int p,int t,int pos)
{
if(sign)return;
int cnt=0;
cho[p]=pro[pos];
if(p==t)
{
set <int> c;
for(int i=0;i<p+1;i++)
for(int j=i+1;j<=p+1;j++)
c.insert(cho[j]-cho[i]);
for(int i=1;i<p1;i++)
vis[arr[i]]=1;
set <int> :: iterator it;
for(it=c.begin();it!=c.end();it++)
{
if(vis[*it])
{
// cout<<vis[*it]<<endl;
cnt++;
vis[*it]=0;
}
}
if(cnt==p1-1)
sign=1;
return;
}
for(int i=pos+1;i<p2-1;i++)
dfs(p+1,t,i);
}
int main()
{
int n,cnt=0,tmp;
set <int> s,x;
while(scanf("%d",&n)&&n)
{
printf("Case %d:\n",++cnt);
sign=0;
memset(vis,0,sizeof(vis));
p1=1;
p2=0;
s.clear();
x.clear();
for(int i=0;i<n;i++)
{
scanf("%d",&tmp);
s.insert(tmp);
}
set <int> ::iterator it;
if(s.size()==1)
{
it=s.begin();
printf("2\n%d %d\n",0,*it);
continue;
}
else if(s.size()==2)
{
it=s.begin();
printf("3\n%d %d",0,*it);
printf(" %d\n",*(++it));
continue;
}
for(it=s.begin();it!=s.end();it++)
arr[p1++]=*it;
arr[0]=0;
for(int i=0;i<p1;i++)
for(int j=i+1;j<p1;j++)
x.insert(arr[j]-arr[i]);
for(it=x.begin();it!=x.end();it++)
pro[p2++]=*it;
for(int i=1;i<=5;i++)
{
cho[0]=0;
cho[i+1]=pro[p2-1];
for(int j=1;j<p2-1;j++)
{
dfs(1,i,j);
if(sign)
{
printf("%d\n",i+2);
printf("%d",cho[0]);
for(int k=1;k<=i+1;k++)
printf(" %d",cho[k]);
printf("\n");
break;
}
}
if(sign)break;
}
}
return 0;
}