忘写题解了,经典的最大密度子图
可以类似分数规划的做,二分密度,然后转化为最大权闭合子图做,判断是否大于0
注意方案的输出
1 const eps=1e-6; 2 lim=1e-12; 3 inf=1000000007; 4 type node=record 5 po,next:longint; 6 flow:double; 7 end; 8 9 var e:array[0..800010] of node; 10 numh,h,cur,pre,p,x,y:array[0..2010] of longint; 11 v:array[0..2010] of boolean; 12 d:array[0..2010] of double; 13 len,i,n,m,t,ans:longint; 14 l,r,mid:double; 15 16 function min(a,b:double):double; 17 begin 18 if a>b then exit(b) else exit(a); 19 end; 20 21 procedure add(x,y:longint;f:double); 22 begin 23 inc(len); 24 e[len].po:=y; 25 e[len].flow:=f; 26 e[len].next:=p[x]; 27 p[x]:=len; 28 end; 29 30 procedure build(x,y:longint;f:double); 31 begin 32 add(x,y,f); 33 add(y,x,0); 34 end; 35 36 function sap:double; 37 var u,i,j,tmp,q:longint; 38 neck:double; 39 begin 40 fillchar(numh,sizeof(numh),0); 41 fillchar(h,sizeof(h),0); 42 numh[0]:=t+1; 43 u:=0; 44 sap:=0; 45 neck:=inf; 46 for i:=0 to t do 47 cur[i]:=p[i]; 48 49 while h[0]<t+1 do 50 begin 51 d[u]:=neck; 52 i:=cur[u]; 53 while i<>-1 do 54 begin 55 j:=e[i].po; 56 if (e[i].flow>lim) and (h[u]=h[j]+1) then 57 begin 58 neck:=min(neck,e[i].flow); 59 pre[j]:=u; 60 cur[u]:=i; 61 u:=j; 62 if u=t then 63 begin 64 sap:=sap+neck; 65 while u<>0 do 66 begin 67 u:=pre[u]; 68 j:=cur[u]; 69 e[j].flow:=e[j].flow-neck; 70 e[j xor 1].flow:=e[j xor 1].flow+neck; 71 end; 72 neck:=inf; 73 end; 74 break; 75 end; 76 i:=e[i].next; 77 end; 78 if i=-1 then 79 begin 80 dec(numh[h[u]]); 81 if numh[h[u]]=0 then break; 82 q:=-1; 83 tmp:=t; 84 i:=p[u]; 85 while i<>-1 do 86 begin 87 j:=e[i].po; 88 if e[i].flow>lim then 89 if h[j]<tmp then 90 begin 91 q:=i; 92 tmp:=h[j]; 93 end; 94 i:=e[i].next; 95 end; 96 h[u]:=tmp+1; 97 inc(numh[h[u]]); 98 cur[u]:=q; 99 if u<>0 then 100 begin 101 u:=pre[u]; 102 neck:=d[u]; 103 end; 104 end; 105 end; 106 end; 107 108 function dfs(x:longint):boolean; 109 var i,y:longint; 110 begin 111 if x=t then exit(true); 112 i:=p[x]; 113 v[x]:=true; 114 while i<>-1 do 115 begin 116 y:=e[i].po; 117 if (e[i].flow>lim) and not v[y] then 118 if dfs(y) then exit(true); 119 i:=e[i].next; 120 end; 121 exit(false); 122 end; 123 124 function check(w:double):boolean; 125 var i:longint; 126 f:double; 127 begin 128 len:=-1; 129 fillchar(p,sizeof(p),255); 130 for i:=1 to m do 131 begin 132 build(x[i]+m,i,inf); 133 build(y[i]+m,i,inf); 134 build(i,t,1); 135 end; 136 for i:=1 to n do 137 build(0,i+m,w); 138 f:=sap; 139 if m-f>0 then 140 begin 141 ans:=0; 142 for i:=1 to n do 143 begin 144 fillchar(v,sizeof(v),false); 145 if dfs(i+m) then inc(ans); 146 end; 147 exit(true); 148 end; 149 exit(false); 150 end; 151 152 begin 153 readln(n,m); 154 for i:=1 to m do 155 readln(x[i],y[i]); 156 t:=n+m+1; 157 l:=0; 158 r:=m; 159 while l+eps<r do 160 begin 161 mid:=(l+r)/2; 162 if check(mid) then l:=mid 163 else r:=mid; 164 end; 165 if m=0 then ans:=1; //必须要选 166 writeln(ans); 167 end.