题目大意:
https://www.luogu.org/problemnew/show/P1282
当知道 总和 及 单行的和
就可以算出差值的大小
1 2 3 4(单行和l=10)
8 7 6 5
(总和s=36)
则上下行的差值为 |l-(s-l)|
#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; int n,a[1005],b[1005],dp[1005][5005]; /// dp[i][j]到第i块牌时 使单行和为j至少需要翻牌的次数 int main() { while(~scanf("%d",&n)) { int s=0; for(int i=0;i<n;i++) { scanf("%d%d",&a[i],&b[i]); s+=a[i]+b[i]; /// 计算总和 } // 因为牌上的数最大为6 最小为1 则差值的范围为 0到5 memset(dp,INF,sizeof(dp)); dp[0][b[0]]=1; dp[0][a[0]]=0; for(int i=1;i<n;i++) for(int j=0;j<=5*n;j++) { /// n块牌各种单行和的翻牌情况 if(j-a[i]>=0) dp[i][j]=min(dp[i][j],dp[i-1][j-a[i]]); /// a[i]在上面 则从j-a[i]转移到j 不需要翻牌 if(j-b[i]>=0) dp[i][j]=min(dp[i][j],dp[i-1][j-b[i]]+1); /// b[i]在下面 则从j-b[i]转移到j需要翻牌 应该+1 } int minc=INF, mins=INF; for(int i=0;i<=5*n && i<=s;i++) if(dp[n-1][i]!=INF) { // 单行和为i的情况存在 if(fabs(i-(s-i))<mins) { // 这种情况得到的上下行差值更小 mins=fabs(i-(s-i)); minc=dp[n-1][i]; } else if(fabs(i-(s-i))==mins) minc=min(minc,dp[n-1][i]); } printf("%d ",minc); } return 0; }