首页 > 代码库 > 【Vijos1222】等值拉面(DP)

【Vijos1222】等值拉面(DP)

题意:有N个数对(a[i],b[i])

每次可以把(x,y)变成(x+a[i],y+b[i])或(x+b[i],x+a[i]),后者称为交换一次

求使abs(x-y)最小时的最小交换次数

n<=1000 1<=a[i],b[i]<=6

思路:设dp[i,j]为前i个数对,使x-y=j时的最小交换次数 转移即可

 1 const oo=100000;
 2 var dp:array[0..1,-6100..6100]of longint;
 3     a,b:array[1..1100]of longint;
 4     n,i,v,j,t,ans:longint;
 5 
 6 function min(x,y:longint):longint;
 7 begin
 8  if x<y then exit(x);
 9  exit(y);
10 end;
11 
12 begin
13  
14  readln(n);
15  for i:=1 to n do read(a[i],b[i]);
16  v:=0;
17  fillchar(dp[v],sizeof(dp[v]),$1f);
18  dp[0,0]:=0;
19  for i:=0 to n-1 do
20  begin
21   v:=1-v; fillchar(dp[v],sizeof(dp[v]),$1f);
22   for j:=-5*i to 5*i do
23    if dp[1-v,j]<oo then
24    begin
25     t:=j+a[i+1]-b[i+1];
26     dp[v,t]:=min(dp[v,t],dp[1-v,j]);
27     t:=j+b[i+1]-a[i+1];
28     dp[v,t]:=min(dp[v,t],dp[1-v,j]+1);
29    end;
30 //  print;
31  end;
32  ans:=oo;
33  for i:=0 to 5*n do
34  begin
35   ans:=min(ans,min(dp[v,i],dp[v,-i]));
36   if ans<oo then break;
37  end;
38  writeln(ans);
39  
40 end.

 

【Vijos1222】等值拉面(DP)