牛客周赛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;
}