线性规划与网络流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
原文地址:https://www.cnblogs.com/Randolph87/p/3603852.html