新年趣事之打牌(Vijos1071)

算法:DP

分析:前两种情况好解决,用个背包可以轻松搞定,看f[m]是否=0或者是否>1,这两种情况都是无解的。
      然后就是记录路径了,再开一个数组,记录每个容量的背包下的选择。最后输出一下即可。{记录的是编号,无需快排……}

program Vijos1071;

const
 maxn=100;
 maxw=10000;
 
var
 n,m:longint;
 f,w:array [0..maxw] of longint;
 a:array [0..maxn] of longint;
 b:array [0..maxn] of boolean;
 
procedure init;
var
 i:longint;
begin
 readln(m);
 readln(n);
 for i:=1 to n do readln(a[i]);
end;

procedure main;
var
 i,j:longint;
begin
 f[0]:=1;
 for i:=1 to n do 
  begin
   for j:=m downto a[i] do
    begin
     if f[j-a[i]]>0 then
      begin
       inc(f[j],f[j-a[i]]);  
       if f[j]=1 then w[j]:=i;{这里a[]是有序的,因此第一次确定的f[j]就是这条路径上的一个确定的选择。}
      end;
    end;
  end;
end;

procedure outit;
var
 i,t,rest:longint;
begin
 if f[m]=0 then 
  begin
   writeln(0);
   close(input);
   close(output);
   halt;
  end;
 if f[m]>1 then 
  begin
   writeln(-1);
   close(input);
   close(output);
   halt;
  end;  
 {输出。}
 t:=w[m];
 rest:=m;
 while t>0 do
  begin
   b[t]:=true;
   dec(rest,a[t]);
   t:=w[rest];
  end; 
 for i:=1 to n do if not b[i] then write(i,' ');
 writeln;
end;

begin
 assign(input,'VJ1071.in'); reset(input);
 assign(output,'VJ1071.out'); rewrite(output);
 
 init;
 main;
 outit;
 
 close(input); close(output);
end.


 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值