神奇了
朴素的做法不难想,二分图最大匹配(汗,我其实还是想了一会,太弱了)
左边点集为能打的属性值,右边把武器作为一个点
武器和两个属性连边,
然后和superhero那题差不多,顺次找匹配,找不到了就退
然后分析一下规模,感觉能卡过去,于是就真卡过去了(……)
其实,因为n很大,每次找匹配要fillchar一下visit数组很浪费时间
于是就加了个队列记录前一次访问过的点
竟然就过去了……论常数优化的重要
1 type node=record 2 next,point:longint; 3 end; 4 5 var edge:array[0..2000010] of node; 6 v:array[0..1000000] of boolean; 7 p:array[0..10010] of longint; 8 q,cx,cy:array[0..1000010] of longint; 9 j,t,s,n,i,x,y,ans,max:longint; 10 11 procedure add(x,y:longint); 12 begin 13 inc(s); 14 edge[s].point:=y; 15 edge[s].next:=p[x]; 16 p[x]:=s; 17 end; 18 19 function dfs(u:longint):boolean; 20 var i,j:longint; 21 begin 22 i:=p[u]; 23 while i<>0 do 24 begin 25 j:=edge[i].point; 26 if not v[j] then 27 begin 28 v[j]:=true; 29 inc(t); 30 q[t]:=j; 31 if (cy[j]=0) or dfs(cy[j]) then 32 begin 33 cx[u]:=j; 34 cy[j]:=u; 35 exit(true); 36 end; 37 end; 38 i:=edge[i].next; 39 end; 40 exit(false); 41 end; 42 43 begin 44 readln(n); 45 for i:=1 to n do 46 begin 47 readln(x,y); 48 add(x,i); 49 add(y,i); 50 if x>max then max:=x; 51 if y>max then max:=y; 52 end; 53 ans:=max; 54 for i:=1 to max do 55 if cx[i]=0 then 56 begin 57 for j:=1 to t do 58 v[q[j]]:=false; //关键啊,能不写fillchar就不写 59 t:=0; 60 if not dfs(i) then 61 begin 62 ans:=i-1; 63 break; 64 end; 65 end; 66 writeln(ans); 67 end.
然后去看了一下正解,感觉真的不容易想到:
还是把属性值看做点,把武器看做连接两个属性值的边(无向边)
1.对于一个联通块,假如不含环(就是一棵树),那么必定可以满足其中任意的p-1个点。
2.对于一个联通块,假如含环,那么必定全部的p个点都能满足。
然后就可以利用并查集优越的时空复杂度了,