线性规划与网络流24题 魔术球

题目描述 Description



    假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2,3,…的球。

    (1)每次只能在某根柱子的最上面放球。

    (2)在同一根柱子中,任何 2 个相邻球的编号之和为完全平方数。

    试设计一个算法,计算出在 n 根柱子上最多能放多少个球。例如,在 4 根柱子上最多可放 11 个球。

    对于给定的 n,计算在 n 根柱子上最多能放多少个球。



输入描述 Input Description



    第 1 行有 1 个正整数 n,表示柱子数。



输出描述 Output Description



    将 n 根柱子上最多能放的球数以及相应的放置方案输出



    第一行是球数。接下来的 n 行,每行是一根柱子上的球的编号。



样例输入 Sample Input



    4



样例输出 Sample Output



    11



    1 8 



    2 7 9 



    3 6 10 



    4 5 11



 

就不多说了,如果i<j,i+j是一个完全平方数,就从i向j连一条边

然后求最小路径覆盖,所以可以转化成二分图最大匹配,所以又可以转化成网络流

本来是想用二分图匹配的匈牙利来做,但是每一次都要重新构图,所以还是用网络流了

后来想到匈牙利只要加一个条件就行了,只要x没有匹配就可以从这里增广,每一次都只是加边就行了,比网络流快了很多(不过多种方案,答案跟标准答案不一样,网络流是把一个地方改成downto才对的,二分图就没办法了,不过还是贴一下吧)

 

 1 const

 2     maxn=1600;

 3     maxm=1000000;

 4 var

 5     n,k,i,p,tot,time:longint;

 6     first,next,last:array[0..maxm]of longint;

 7     flagx:array[0..maxn]of boolean;

 8     flag,link,nextball:array[0..maxn]of longint;

 9 

10 procedure insert(x,y:longint);

11 begin

12     inc(tot);

13     last[tot]:=y;

14     next[tot]:=first[x];

15     first[x]:=tot;

16 end;

17 

18 function path(x:longint):boolean;

19 var

20     i:longint;

21 begin

22     i:=first[x];

23     while i<>0 do

24       begin

25         if last[i]<=n then

26         if flag[last[i]]<>time then

27         begin

28           flag[last[i]]:=time;

29           if (link[last[i]]=0)or(path(link[last[i]])) then

30           begin

31             link[last[i]]:=x;

32             flagx[x]:=true;

33             exit(true);

34           end;

35         end;

36         i:=next[i];

37       end;

38     exit(false);

39 end;

40 

41 procedure work;

42 var

43     i:longint;

44 begin

45     for i:=1 to n-1 do

46       if flagx[i]=false then

47       begin

48         inc(time);

49         if path(i) then inc(p);

50       end;

51 end;

52 

53 procedure print;

54 var

55     i,j:longint;

56 begin

57     for i:=1 to n do

58       nextball[link[i]]:=i;

59     inc(time);

60     for i:=1 to n do

61       if flag[i]<>time then

62       begin

63         j:=i;

64         while j<>0 do

65           begin

66             flag[j]:=time;

67             write(j,' ');

68             j:=nextball[j];

69           end;

70         writeln;

71       end;

72 end;

73 

74 begin

75     read(k);

76     while n-p<=k do

77       begin

78         inc(n);

79         for i:=1 to n-1 do

80           if sqr(trunc(sqrt(i+n)))=i+n then insert(i,n);

81         work;

82       end;

83     dec(n);

84     writeln(n);

85     for i:=1 to n do

86       flagx[i]:=false;

87     for i:=1 to n do

88       link[i]:=0;

89     work;

90     print;

91 end.
二分图匈牙利

 

  1 const

  2     maxn=3200;

  3 var

  4     map,a:array[0..maxn,0..maxn]of longint;

  5     dis,vh,his,pre,next:array[0..maxn]of longint;

  6     f:array[0..maxn]of boolean;

  7     k,n,p,i,j,aug:longint;

  8     flag:boolean;

  9 

 10 procedure work;

 11 var

 12     i,j,k,min:longint;

 13 begin

 14     for i:=1 to n do

 15       begin

 16         dis[i]:=0;

 17         dis[i+1600]:=0;

 18       end;

 19     dis[0]:=0;

 20     dis[3200]:=0;

 21     for i:=1 to 2*n+2 do

 22       vh[i]:=0;

 23     vh[0]:=2*n+2;

 24     aug:=maxlongint;

 25     i:=0;

 26     while dis[0]<2*n+2 do

 27       begin

 28         his[i]:=aug;

 29         flag:=false;

 30         for j:=a[i,0] downto 1 do

 31           if (map[i,a[i,j]]>0)and(dis[i]=dis[a[i,j]]+1) then

 32           begin

 33             flag:=true;

 34             pre[a[i,j]]:=i;

 35             if aug>map[i,a[i,j]] then aug:=map[i,a[i,j]];

 36             i:=a[i,j];

 37             if i=3200 then

 38             begin

 39               inc(p,aug);

 40               while i<>0 do

 41                 begin

 42                   k:=pre[i];

 43                   dec(map[k,i],aug);

 44                   inc(map[i,k],aug);

 45                   i:=k;

 46                 end;

 47               aug:=maxlongint;

 48             end;

 49             break;

 50           end;

 51         if flag then continue;

 52         min:=2*n+1;

 53         for j:=1 to a[i,0] do

 54           if (map[i,a[i,j]]>0)and(dis[a[i,j]]<min) then min:=dis[a[i,j]];

 55         dec(vh[dis[i]]);

 56         if vh[dis[i]]=0 then break;

 57         dis[i]:=min+1;

 58         inc(vh[dis[i]]);

 59         if i<>0 then

 60         begin

 61           i:=pre[i];

 62           aug:=his[i];

 63         end;

 64       end;

 65 end;

 66 

 67 procedure print;

 68 var

 69     i,j:longint;

 70 begin

 71     for i:=1 to n do

 72       for j:=1 to a[i,0] do

 73         if map[i,a[i,j]]=0 then next[i]:=a[i,j]-1600;

 74     for i:=1 to n do

 75       if f[i]=false then

 76       begin

 77         j:=i;

 78         while j<>0 do

 79           begin

 80             f[j]:=true;

 81             write(j,' ');

 82             j:=next[j];

 83           end;

 84         writeln;

 85       end;

 86 end;

 87 

 88 begin

 89     read(k);

 90     n:=0;

 91     while n-p<=k do

 92       begin

 93           inc(n);

 94         inc(a[0,0]);

 95         a[0,a[0,0]]:=n;

 96         inc(map[0,n]);

 97         inc(a[n+1600,0]);

 98         a[n+1600,a[n+1600,0]]:=3200;

 99         inc(map[n+1600,3200]);

100         for i:=1 to n-1 do

101           if sqr(trunc(sqrt(i+n)))=i+n then

102           begin

103             inc(map[i,n+1600]);

104             inc(a[i,0]);

105             a[i,a[i,0]]:=n+1600;

106             inc(a[n+1600,0]);

107             a[n+1600,a[n+1600,0]]:=i;

108           end;

109         work;

110       end;

111     dec(n);

112     fillchar(map,sizeof(map),0);

113     dec(a[0,0]);

114     for i:=1 to n do

115       begin

116         map[0,i]:=1;

117         map[i+1600,3200]:=1;

118         if a[i,a[i,0]]=n+1+1600 then dec(a[i,0]);

119         for j:=1 to a[i,0] do

120           map[i,a[i,j]]:=1;

121       end;

122     work;

123     writeln(n);

124     print;

125 end.
网络流sap

 

你可能感兴趣的:(网络流)