POJ 2749

POJ 2749

题目大意:给出若干个牛棚的坐标,现有两个点d1, d2(交通枢纽点),d1, d2之间有一条路(本题两点的路程为横坐标之差和纵坐标之差的绝对值),求牛棚连到d1,或d2,任意两个牛棚之间最大值的最小值是多少。他还加了一个约束条件,就是给出a对牛棚,每对牛棚是不能连在同一个枢纽点,再给出b对牛棚,每对牛棚一定要连在同一个枢纽点。

解:上网找做法,说这个是一种2sat模型,属于np模型、主要是讨论有节点关系为一定共存和一定不共存这样一些的图。这道题目也是一样(要么不能一起,要么一起),核心思想是二分答案(和noip2010 no3类似,有时间复习),然后建图讨论是否可行。设x为x处于d1,x+n为x处于d2,然后讨论他们。(建图:定义,如果有a->b说明选择了a则一定要选则b)如果dist[i][1]+dist[j][1]>mid,说明如果点i和点j都连在d1则一定超过,所以对与i连d1时,j一定只能连d2,所以连上一条i->j+n的边,而如果j连d1,那么i必须连d2,所以连边j->i+n,然后根据构图的对称性(这个要看论文仔细钻研)可知选择了一个点,他和他连向的点一定是一个强联通分量,所以tarjan一次,然后找出如果存在col[i]=col[i+n]则说明这幅图不能成立(显然,连d1的同时练d2才成立,显然违反题意了)

注释:好二,因为边的数量又算少了,wa了好多次+浪费了一个多小时。虽然不在乎ac率了,可无谓的错误还是不应该的。

View Code
  1 const
2 maxn=522 *2;
3 bilibili=maxlongint >> 1;
4 inf=55555555;
5 type
6 data=record
7 dest, next: longint;
8 end;
9 dota=record
10 a, b: longint;
11 end;
12 var
13 edge: array[1..maxn * maxn]of data;
14 dfn, low, s, vect, col:array[1..maxn]of longint;
15 hate, friend: array[1..maxn]of dota;
16 dist: array[1..maxn, 1..2]of longint;
17 visit: array[1..maxn]of boolean;
18 sx1, sx2, sy1, sy2, time, d, color, stot, tot, n, a, b, ans: longint;
19 procedure add(x, y: longint);
20 begin
21 inc(tot);
22 with edge[tot] do begin
23 dest := y;
24 next := vect[x];
25 vect[x] := tot;
26 end;
27 end;
28
29 procedure init;
30 var
31 i, j, x, y: longint;
32 begin
33 readln(n, a, b);
34 readln(sx1, sy1, sx2, sy2);
35 d := abs(sx1-sx2)+abs(sy1-sy2);
36 for i := 1 to n do begin
37 readln(x, y);
38 dist[i][1] := abs(sx1-x) + abs(sy1-y);
39 dist[i][2] := abs(sx2-x) + abs(sy2-y);
40 end;
41 for i := 1 to a do readln(hate[i].a, hate[i].b);
42 for i := 1 to b do readln(friend[i].a, friend[i].b);
43 end;
44
45 procedure tarjan(x: longint);
46 var
47 i, u: longint;
48 begin
49 inc(time); inc(stot);
50 dfn[x] := time; low[x] := dfn[x];
51 s[stot] := x; visit[x] := true;
52 i := vect[x];
53 while i<>0 do
54 with edge[i] do begin
55 if dfn[dest]=0 then begin
56 tarjan(dest);
57 if low[dest]<low[x] then low[x] := low[dest];
58 end
59 else begin
60 if visit[dest] then
61 if dfn[dest]<low[x] then low[x] := dfn[dest];
62 end;
63 i := next;
64 end;
65 if dfn[x]=low[x] then begin
66 inc(color);
67 repeat
68 u := s[stot];
69 visit[u] := false;
70 dec(stot);
71 col[u] := color;
72 until u=x;
73 end;
74 end;
75
76 function check(key: longint): boolean;
77 var
78 i, j, x, y: longint;
79 begin
80 tot := 0;
81 fillchar(vect, sizeof(vect), 0);
82 for i := 1 to n - 1 do
83 for j := i+1 to n do begin
84 if dist[i][1]+dist[j][1]>key then begin add(i, j+n); add(j, i+n); end;
85 if dist[i][2]+dist[j][2]>key then begin add(i+n, j); add(j+n, i); end;
86 if dist[i][1]+dist[j][2]+d>key then begin add(i, j); add(j+n, i+n); end;
87 if dist[i][2]+dist[j][1]+d>key then begin add(i+n, j+n); add(j, i); end;
88 end;
89 for i := 1 to a do begin
90 x := hate[i].a; y := hate[i].b;
91 add(x, y+n); add(x+n, y); add(y, x+n); add(y+n, x);
92 end;
93 for i := 1 to b do begin
94 x := friend[i].a; y := friend[i].b;
95 add(x, y); add(x+n, y+n); add(y, x); add(y+n, x+n);
96 end;
97
98 color := 0; stot := 0; time := 0;
99 fillchar(col, sizeof(col), 0);
100 fillchar(dfn, sizeof(dfn), 0);
101 fillchar(visit, sizeof(visit), 0);
102 for i := 1 to n*2 do
103 if col[i]=0 then tarjan(i);
104
105 for i := 1 to n do
106 if col[i]=col[i+n] then exit(false);
107 exit(true);
108 end;
109
110 procedure main;
111 var
112 st, ed, mid: longint;
113 begin
114 st := 0; ed := inf; ans := -1;
115 while st<=ed do begin
116 mid := (st+ed) >> 1;
117 if check(mid) then begin
118 ed := mid -1;
119 ans := mid;
120 end
121 else st := mid + 1;
122 end;
123 end;
124
125 procedure print;
126 begin
127 writeln(ans);
128 end;
129
130 begin
131 assign(input,'1.txt'); reset(input);
132 while not(seekeof) do begin
133 init;
134 main;
135 print;
136 end;
137 end.



原文地址:https://www.cnblogs.com/wmzisfoolish/p/2435184.html