SSL 1638 拔河比赛
题目描述:
一个学校举行拔河比赛,所有人被分成了两组,每个人必须且只能够在其中一组,要求两个组的人数相差不能超过1,且两个组内所有人的体重加起来进可能地接近。
样例输入:
3
100
90
200
样例输出:
190 200
解题思路:
由于单个人最大重量比超过450,是一个极小的值,因此可以考虑将解(即重量)本身作为状态中的一个参量,将问题转换为判定性问题,通过判定解是否存在来找到最优解。
设
f
i
,
j
,
k
f_{i,j,k}
fi,j,k 表示从
i
i
i 个人中选
j
j
j 个人,组成总重量为
k
k
k 的组合是否可能存在。
由此可推知,
f
i
,
j
,
k
f_{i,j,k}
fi,j,k 的状态无非就是从这两种状态转移而来的:
若不选第
i
i
i 个人,那么从
i
i
i 个人中选
j
j
j 个人无非就转移成了 从
i
−
1
i-1
i−1 个人中选
j
j
j 个人,也就是
f
i
−
1
,
j
,
k
f_{i-1,j,k}
fi−1,j,k。
若选第
i
i
i 个人,那么 从
i
i
i 个人中选
j
j
j 个人无非就转移成了从
i
−
1
i-1
i−1 个人中选
j
−
1
j-1
j−1 个人,组成重量为
k
−
w
i
k-w_i
k−wi 的组合,即
f
i
−
1
,
j
−
1
,
k
−
w
i
f_{i-1,j-1,k-w_i}
fi−1,j−1,k−wi。
那么即可推出动态转移方程:
f
i
,
j
,
k
=
f
i
−
1
,
j
,
k
o
r
f
i
−
1
,
j
−
1
,
k
−
w
i
f_{i,j,k}=f_{i-1,j,k}\ \ \ or\ \ \ f_{i-1,j-1,k-w_i}
fi,j,k=fi−1,j,k or fi−1,j−1,k−wi
这样子一来,最优解就是: 当 f n , n / 2 , i = t r u e f_{n,n/2,i}=true fn,n/2,i=true 且 f n , n / 2 + n m o d 2 , i = t u r e f_{n,n/2+n~mod~2,i}=ture fn,n/2+n mod 2,i=ture 时的最小 i i i
CODE:
#include <iostream>
#include <cmath>
using namespace std;
int n,w[110],sum=0,ans1,ans2=0;
bool f[110][45001]={false}; //由于f[i]的转移只与f[i-1]有关,因此可以省去一维
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>w[i],sum+=w[i];
f[0][0]=true; //初始条件
for(int i=1;i<=n;i++) //枚举总共人数
{
for(int j=1;j<=i/2+1;j++) //枚举每一组的人数
{
for(int k=j*450;k>=max(j,w[i]);k--) //枚举每一组人数可能的重量
{
f[j][k]=f[j][k]||f[j-1][k-w[i]]; //状态转移
}
}
}
ans1=(1e9);
for(int i=n/2;i<=n/2*450;i++) //找到最优解
if(f[n/2][i]&&f[n/2+n%2][sum-i])
{
if(abs(ans1-ans2)>abs(i-sum+i))
ans1=i,ans2=sum-i;
}
cout<<min(ans1,ans2)<<" "<<max(ans1,ans2);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!