#1036. 牛场围栏

题目描述

John计划为他的牛场建一个围栏,以限制奶牛们的活动。他有N种可以建造围栏的木料,长度分别是L1,L2…LN, 每种长度的木料无限。

修建时,他将把所有选中的木料拼接在一起,因此围栏的长度就是他使用的木料长度之和。但是聪明的John很快发现很多长度都是不能由这些木料长度相加得到的,于是决定在必要的时候把这些木料砍掉一部分 以后再使用。

不过由于John比较节约,他给自己规定:任何一根木料最多只能削短M米。当然,每根木料削去的木料 长度不需要都一样。不过由于测量工具太原始,John只能准确的削去整数米的木料,因此,如果他有两种长度分别是 7和11的木料,每根最多只能砍掉1米,那么实际上就有4种可以使用的木料长度,分别是6, 7, 10, 11。

Clevow是John的牛场中的最聪明的奶牛,John请她来设计围栏。Clevow不愿意自己和同伴在游戏时受到围栏的 限制,于是想刁难一下John,希望John的木料无论经过怎样的加工,长度之和都不可能得到她设计的围栏总长度。 不过Clevow知道,如果围栏的长度太小,John很快就能发现它是不能修建好的。因此她希望得到你的帮助,找 出无法修建的最大围栏长度。

输入格式

输入文件的第一行包含两个整数N, M (1 < N < 100, 0 < M < 3000),分别表示木料的种类和每根木料削去的最大值。

以下各行每行一个整数li (1 < li < 3000 ),表示第i根木料的原始长度。

输出格式

输出文件仅一行,包含一个整数,表示不能修建的最大围栏长度。

如果任何长度的围栏都可以修建或者这个最大值不存在,输出-1。

样例

样例输入

 2 1
7 
11

样例输出

 15

代码:

#include<bits/stdc++.h>
 using namespace std;
 int n,m;
 int length[4001234],minl,maxl,kinum;
 int dis[3001];
 bool used[3001];
 int way[3001][3001];
 const int INF=1401401003;
 int gcd(int x,int y)
 {
if(y==0) return x;
return gcd(y,x%y);
 }
 void dijkstra()
 {
dis[0]=0;
used[0]=1;
int nownum=0;
for(int i=0;i<minl;i++)
{
dis[i]=way[0][i];
}
for(int i=1;i<minl;i++)
{
int minle=INF+1,minnu=-1;
for(int j=0;j<minl;j++)
{
if(used[j]) continue;
if(minle>dis[j])
{
minnu=j;
minle=dis[j];
}
}
used[minnu]=1;
for(int j=1;j<minl;j++)
{
if(j==minnu) continue;
dis[j]=min(dis[j],dis[minnu]+way[minnu][j]);
}
}
 }
 int main()
 {
int asd=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int len;
cin>>len;
for(int j=0;j<=m;j++)
{
if(j>=len) break;
length[++kinum]=len-j;
}
}
asd=length[1];
for(int i=2;i<=kinum;i++)
{
asd=gcd(max(asd,length[i]),min(asd,length[i]));
if(asd==1) break;
}
minl=INF;
for(int i=1;i<=kinum;i++)
{
minl=min(minl,length[i]);
}
if(asd!=1||minl==1)
{
cout<<"-1\n";
return 0;
}
//Input is done.
for(int i=0;i<minl;i++)
for(int j=0;j<minl;j++)way[i][j]=INF;
for(int i=0;i<minl;i++) way[i][i]=0;
for(int i=1;i<=kinum;i++)
{
for(int j=0;j<minl;j++)
{
int pg=(j+length[i])%minl;
way[j][pg]=min(way[j][pg],length[i]);
}
}
dijkstra();
int ans=dis[1];
for(int i=1;i<minl;i++)
{
if(dis[i]>ans) ans=dis[i];
}
ans-=minl;
cout<<ans<<endl;
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值