1. 程式人生 > >【動態規劃】拔河比賽 (ssl 1638)

【動態規劃】拔河比賽 (ssl 1638)

拔河比賽

Description

一個學校舉行拔河比賽,所有的人被分成了兩組,每個人必須(且只能夠)在其中的一組,要求兩個組的人數相差不能超過1,且兩個組內的所有人體重加起來儘可能地接近。

Input

輸入資料的第1行是一個n,表示參加拔河比賽的總人數,n<=100,接下來的n行表示第1到第n個人的體重,每個人的體重都是整數(1<=weight<=450)。

Output

輸出資料應該包含兩個整數:分別是兩個組的所有人的體重和,用一個空格隔開。注意如果這兩個數不相等,則請把小的放在前面輸出。

Sample Input

3

100

90

200

Sample Output

190 200

題目大意:

有n個人,每個人有自己的重量,把他們分成兩對,當n為偶數時,兩隊的人要一樣,當n為基數時,兩隊的人的差值只能為1,求兩隊的重量之差最小是多少

解題方法:

用f[i][j][k]來表示前i個人選j個人重量為k是否可能,但因為f[i][j][k]只和f[i-1][j-1~0]的數有關,我們可以表示為f[j][k],在倒著來就行了,然後在一個一個往後推

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,num,sum,a[105],f[105][45005];
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf
("%d",&a[i]); sum+=a[i];//求總和 } num=sum/2;//求一半 f[0][0]=1;//預處理 for (int i=1;i<=n;i++)//n個人 for (int j=min(n/2,i-1);j>=0;j--)//min是因為f只需要n的一半就行了,但當前只有n-1個人所以求最小值可以節省時間 for (int k=0;k<=j*450;k++)//之前選了幾個人,現在最多的就是j*450 if (f[j][k]) f[j+1][k+a[i]]=1;//如果之前選j個人重量為k是可以的,那麼選j+1個人重量為k+a[i]也是可以的 for (int i=0;1 ;i++)//離中間值有多遠 { if (f[n/2][num+i]) //比中間值大i { printf("%d %d",min(num+i,sum-num-i),max(num+i,sum-num-i));//num+i是第1隊,剩下的就是第二隊=sum-(num+i)=sum-num-i break;//找到就退出 } if (f[n/2][num-i]) //比中間值小i { printf("%d %d",min(num-i,sum-num+i),max(num-i,sum-num+i));//num-i是第1隊,剩下的就是第二隊=sum-(num-i)=sum-num+i break;//找到就退出 } } }