题意:给成一组多米诺牌,每个多米诺牌由上面和下面两组数组成,现要求可以翻动颠倒上下,使得多米诺上边的点数和减去下边的点数和的绝对值最小。
思路:不知道自己写的开两个数组的为什么一直wa。照抄了一个同样思路的代码能AC,错误在哪?????
AC代码:
#include <stdio.h>
#include <string.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define N 52010
int dp[N],num[N],s[N/6],t[N/6];
int n;
int main(){
int i,j,m,sum;
sum = 0;
memset(dp,-1,sizeof(dp));
dp[0] = 0;
scanf("%d",&n);
while(n--){
int a,b,i,j;
scanf("%d %d",&a,&b);
sum += a+b;
for(j = sum;j>=0;j--){
if(dp[j] != -1){
int temp = dp[j];
dp[j] = -1;
if(dp[j+a]==-1 || dp[j+a]>temp)
dp[j+a] = temp;
if(dp[j+b]==-1 || dp[j+b]>temp+1)
dp[j+b] = temp+1;
}
}
}
for(i = sum/2;i>=0;i--)
if(dp[i]!=-1){
printf("%d\n",min(dp[i],dp[sum-i]));
break;
}
return 0;
}
WA代码:
#include <stdio.h>
#include <string.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define N 52010
int dp[N],num[N],s[N/6],t[N/6];
int n;
int main(){
int i,j,m,sum;
m = sum = 0;
scanf("%d",&n);
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for(i = 1;i<=n;i++){
scanf("%d %d",&s[i],&t[i]);
m += max(s[i],t[i]);
sum += (s[i]+t[i]);
}
for(i = 1;i<=m;i++)
num[i] = n+1;
for(i = 1;i<=n;i++)
for(j = m-1;j>=0;j--)
if(dp[j]){
dp[j+s[i]] = 1;
num[j+s[i]] = min(num[j+s[i]],num[j]);
dp[j+t[i]] = 1;
num[j+t[i]] = min(num[j+t[i]],num[j]+1);
dp[j] = 0;
num[j] = n+1;
}
for(i = sum/2;i>=0;i--){
if(dp[i] && (j=min(num[i],num[sum-i])) != n+1){
printf("%d\n",j);
break;
}
}
return 0;
}