BZOJ2661 连连看 (费用流)

把所有点拆成两个,将符合条件的两个点x,y连上边,流量为1,费用为-(x+y)。

做一遍最小费用最大流,最后ans div 2即可。

 1 Program bzoj2661;
 2 const INF=2000000000;
 3 var last,next,p,cost,cap,q:array[0..1000000] of longint;
 4     flag1,flag2:array[0..10000] of boolean;
 5     a,c,i,j,x,y,t,s,sum:longint;
 6     b:array[0..1000000] of longint;
 7     pd:array[0..10000] of boolean;
 8     d,ps:array[0..10000] of longint;
 9 function gcd(x,y:longint):longint;
10 begin
11   if y=0 then exit(x) else exit(gcd(y,x mod y));
12 end;
13 procedure add(x,y,f,c:longint);
14 begin
15   inc(sum); next[sum]:=last[x]; last[x]:=sum;
16   p[sum]:=y; q[sum]:=x; cost[sum]:=c; cap[sum]:=f;
17 end;
18 procedure adt(x,y,f,c:longint);
19 begin
20   add(x,y,f,c); add(y,x,0,-c);
21 end;
22 procedure spfa;
23 var i,j,l,r:longint;
24 begin
25   for i:=0 to t  do d[i]:=INF;
26   fillchar(pd,sizeof(pd),false);
27   l:=1; r:=1; pd[s]:=true; b[1]:=s; d[s]:=0;
28   while l<=r do
29     begin
30       i:=last[b[l]];
31       while i<>0 do
32         begin
33           if (cap[i]>0) and (d[p[i]]>d[b[l]]+cost[i]) then
34             begin
35               d[p[i]]:=d[b[l]]+cost[i];
36               ps[p[i]]:=i;
37               if not pd[p[i]] then
38                 begin
39                   inc(r);
40                   b[r]:=p[i];
41                   pd[p[i]]:=true;
42                 end;
43             end;
44           i:=next[i];
45         end;
46       pd[b[l]]:=false;
47       inc(l);
48     end;
49 end;
50 procedure minCmaxF;
51 var x,i,j,cc,f,min:longint;
52 begin
53   f:=0; cc:=0;
54   while true do
55     begin
56       spfa;
57       if d[t]=INF then
58         begin
59           writeln(f div 2,' ',-cc div 2);
60           exit;
61         end;
62       min:=INF;
63       x:=t;
64       while x<>s do
65         begin
66           if cap[ps[x]]<min then min:=cap[ps[x]];
67           x:=q[ps[x]];
68         end;
69       x:=t;
70       while x<>s do
71         begin
72           dec(cap[ps[x]],min);
73           inc(cap[ps[x] xor 1],min);
74           x:=q[ps[x]];
75         end;
76       cc:=cc+min*d[t];
77       f:=f+min;
78     end;
79 end;
80 begin
81   readln(a,c);
82   s:=0;
83   for i:=a to c do
84     for j:=a to c do if (i<>j) then
85       begin
86         x:=trunc(sqrt(abs(i*i-j*j)));
87         if x*x<>abs(i*i-j*j) then continue;
88         if gcd(i,j)<>1 then continue;
89         add(i,j+c,1,-(i+j));
90       end;
91  for i:=a to c do add(0,i,1,0);
92  for i:=a to c do add(i+c,c*2+1,1,0);
93  s:=0; t:=2*c+1;
94  minCmaxF;
95 end.

 

转载于:https://www.cnblogs.com/rpSebastian/p/4133497.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值