回 帖 发 新 帖 刷新版面

主题:[讨论]一道很怪的题

问题描述
给省队选拔赛命题的时候,周老师手下有N个命题人,要命N种不同类型的试题,其中每人命每一类型的试题一题。因为每个命题人对不同题型的掌握程度不同,所以他们编出的试题难度也有不同(这用一个难度数值来表示)。为了尽可能地刁难大家,周老师决定出一张N个题的试卷,每一类型的试题一题,而且所有题的难度值总和最大。

- 输入数据
第一行为N(N <= 20),代表命题人的个数。(40%的数据N<=10)
以后N行,每行N个整数(每个数不超过100),第i行j列的数表示第i个人出的第j种题目的难度大小。

- 输出数据
一行,表示试卷难度的最大值。

- 样例输入
3
50  50  1
10  100 10
100 10  10

- 样例输出
201

[color=008000]这道题谁能告诉我如何用动态规划解,并写出状态转移方程和注释[/color][/color][col[size=3]谢谢[/size]

回复列表 (共8个回复)

沙发

背包问题的变种,把他想成背包问题做,用贪心做

板凳

MS不是动规吧,是网络流吧。。~~~
图:       ------s-------
          |      |      |            
          1      2      3             
              .......                     
          4      5      6
          |      |      |
          -------t-------                                      
图画的比较的恶劣~~~~~~凑合吧
解释:123表示人,456表示题目。途中的“……”1到6这6个点之间在图中每一上一下两个点之间连两个点。其中权值1为相应人编相应题目的难度值,权值2为容量(可走次数)。s为源点,t为汇点。从s到123、从456到t权值1(流量)为无限,“……”中的边权值1为,相应人编相应题目的难度值;所有边的权值2为1。所以此题转化为求图中的最大流(对权值2而言)。
hoho~~~此题顺利转型!用一次增广路就OK了。。囍

3 楼

晕,我突然觉得自己表达很差~~~要:@@@恶补@@@

4 楼

再次归来:
program work;
const maxn=100;
type node1=record
  w,f,c:integer
  end;
type node2=record
  value:integer;
  fa:integer;
 end;
var a:array[1..maxn+2,1..maxn+2] of node1;
  best:array[1..maxn+2] of node2;
  n,maxwork,s,t:integer;
procedure init;
var i,j:integer;
begin
 readln(n);
 fillchar(a,sizeof(a),0);
 for i:=1 to n do
  for j:=n+1 to 2*n do
   begin
   read(a[i,j].w);
   a[i,j].c:=1;
   a[j,i].w:=-a[i,j].w;
   end;
 s:=2*n+1;
 t:=2*n+2;
 for i:=1 to n do
  begin
   a[s,i].c:=1;
   a[n+i,t].c:=1;
  end;
 maxwork:=0;
 end;
function find:boolean;
var i,j:integer;
quit:boolean;
begin
 fillchar(best,sizeof(best),0);
 best[s].value:=1;
 repeat
  quit:=true;
  for i:=1 to 2*n+2 do
     if best[i].value>0 then
    for j:=1 to 2*n+2 do
     if (a[i,j].f<a[i,j].c) then
      if best[i].value+a[i,j].w>best[j].value then
         begin
         best[j].value:=best[i].value+a[i,j].w;
         best[j].fa:=i;
         quit:=false;
         end;
until quit;
if best[t].value>1 then find:=true else find:=false;
end;
procedure add;
var i,j:integer;
begin
 i:=t;
 while i<>s do
  begin
   j:=best[i].fa;
   inc(a[j,i].f);
   a[i,j].f:=-a[j,i].f;
   i:=j
  end;
  inc(maxwork,best[t].value-1);
end;
begin
init;
while find do add;
writeln(maxwork);
end.
另:可能有些变量不同~~~~不过差不多吧

5 楼

嗯,说的没错,这种题一般用最大流做

6 楼

MS  PKU上有原题。。

7 楼

n较小,应该可以搜索吧!

8 楼

网络流不会,只有搜索解:
program xuanbasai;
var
  a:array[1..20,1..20]of longint;
  b:array[1..20]of boolean;
  i,j,n,max:longint;
procedure find( x,y:longint);
var i:longint;
begin
   if x=n+1 then begin  if y>max then max:=y; end
            else begin
              for i:=1 to n do if b[i] then begin
                b[i]:=false;
                find(x+1,y+a[x,i]);
                b[i]:=true;
              end;
            end;
end;

begin
   readln(n);
   for i:=1 to n do begin
     for j:=1 to n do read(a[i,j]);
     readln;
   end;
   fillchar(b,sizeof(b),true);
   for j:=1 to n do begin
     b[i]:=false;
     find(2,a[1,i]);
     b[i]:=true;
   end;
   writeln(max);
   readln;
end.

我来回复

您尚未登录,请登录后再回复。点此登录或注册