bzoj1854

神奇了

朴素的做法不难想,二分图最大匹配(汗,我其实还是想了一会,太弱了)

左边点集为能打的属性值,右边把武器作为一个点

武器和两个属性连边,

然后和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.
View Code

然后去看了一下正解,感觉真的不容易想到:

还是把属性值看做点,把武器看做连接两个属性值的边(无向边)

1.对于一个联通块,假如不含环(就是一棵树),那么必定可以满足其中任意的p-1个点。
2.对于一个联通块,假如含环,那么必定全部的p个点都能满足。

然后就可以利用并查集优越的时空复杂度了,

原文地址:https://www.cnblogs.com/phile/p/4473257.html