牛客周赛86E题
思路
本题容易想到可构成的多边形需最大边MAX小于其他边的和
令多边形周长为C,则有C-MAX>MAX
所以有C>2*MAX且C尽量小
那么可以判断,MAX越小则C容易越小
于是我们可以从小的边枚举
比该边小或等于的均可作为边的材料
最后将所有C中最小的输出即可
若是没有一个边可以构造C则输出-1
值得注意的是 使用比MAX小的边构造时 令排在MAX前的边和为sum
当sum<=MAX时,不可能构成多边形,可跳过
当枚举的边MAX>先前构造成功的最小周长C的一半时,不论如何构造获得的周长一定小于C
如果可以在sum中选取一些边长和s1>MAX的话(s1+s2=sum)
那么必定其他的边长和s2<sum-MAX
预使C要更小则s2须在小于(sum-MAX)的范围内最大
于是到这里可以转换为背包问题
代码
#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;
const int N=1e5+10;
void solve(){
int n,s,ans=N;
cin>>n;
vector<int>v(n+1);
for(int i=1;i<=n;i++)
cin>>v[i];
sort(v.begin()+1,v.end());
s=v[1];
for(int i=3;i<=n;i++){
s+=v[i-1];
if(s<=v[i]) continue;
if(v[i]>=ans/2) break;
vector<int>dp(s);
int maxn=v[i];
for(int j=1;j<i;j++){
for(int k=s-maxn-1;k>=0;k--)
if(k>=v[j]) dp[k]=max(dp[k],dp[k-v[j]]+v[j]);
}
int c=s-dp[s-maxn-1]+maxn;
ans=min(c,ans);
}
if(ans==N){
cout<<"-1"<<endl;
return;
}
cout<<ans<<endl;
}
signed main(){
cin.tie(0);cout.tie(0);
ios::sync_with_stdio(false);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}

京公网安备 11010502036488号