Section 1.3

master
大蒟蒻 9 years ago
parent 8c247bdb18
commit 8daa03e3e4

@ -0,0 +1,97 @@
#include <cstdio>
#include <cstring>
inline int abs(int x) { return x >= 0 ? x : -x; }
inline int min(int a, int b) { return a < b ? a : b; }
const int inf = 0x3f3f3f3f, maxn = 10010, maxm = 1200010;
int head[maxn], next[maxm], to[maxm], ecnt, n, A, B;
int dfn[maxn], low[maxn], stk[maxn], scc[maxn], top, idx, scccnt;
int sx1, sy1, sx2, sy2, sLen, X[maxn], Y[maxn], hate[maxn][2], like[maxn][2],
d[maxn];
inline void addEdge(int f, int t)
{
next[ecnt] = head[f];
head[f] = ecnt;
to[ecnt] = t;
ecnt++;
}
void tarjan(int x)
{
dfn[x] = low[x] = ++idx;
stk[top++] = x;
for (int i = head[x]; ~i; i = next[i])
if (!dfn[to[i]])
tarjan(to[i]), low[x] = min(low[x], low[to[i]]);
else if (!scc[to[i]])
low[x] = min(low[x], dfn[to[i]]);
if (dfn[x] == low[x])
{
scccnt++;
do
scc[stk[--top]] = scccnt;
while (stk[top] != x);
}
}
bool check(int x)
{
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(scc, 0, sizeof(scc));
memset(head, -1, sizeof(head));
ecnt = top = idx = scccnt = 0;
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
{
int l1 = d[i << 1], l2 = d[i << 1 | 1];
int r1 = d[j << 1], r2 = d[j << 1 | 1];
if (l1 + r1 > x)
addEdge(i << 1, j << 1 | 1), addEdge(j << 1, i << 1 | 1);
if (l1 + r2 + sLen > x)
addEdge(i << 1, j << 1), addEdge(j << 1 | 1, i << 1 | 1);
if (l2 + r1 + sLen > x)
addEdge(i << 1 | 1, j << 1 | 1), addEdge(j << 1, i << 1);
if (l2 + r2 > x)
addEdge(i << 1 | 1, j << 1), addEdge(j << 1 | 1, i << 1);
}
for (int i = 1, a, b; i <= A; i++)
{
a = hate[i][0], b = hate[i][1];
addEdge(a << 1, b << 1 | 1);
addEdge(a << 1 | 1, b << 1);
addEdge(b << 1, a << 1 | 1);
addEdge(b << 1 | 1, a << 1);
}
for (int i = 1, a, b; i <= B; i++)
{
a = like[i][0], b = like[i][1];
addEdge(a << 1, b << 1);
addEdge(a << 1 | 1, b << 1 | 1);
addEdge(b << 1, a << 1);
addEdge(b << 1 | 1, a << 1 | 1);
}
for (int i = 1; i <= (n << 1); i++)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; i++)
if (scc[i << 1] == scc[i << 1 | 1])
return false;
return true;
}
int main()
{
scanf("%d%d%d%d%d%d%d", &n, &A, &B, &sx1, &sy1, &sx2, &sy2);
sLen = abs(sx1 - sx2) + abs(sy1 - sy2);
for (int i = 1; i <= n; i++)
scanf("%d%d", X + i, Y + i);
for (int i = 1; i <= n; i++)
d[i << 1] = abs(X[i] - sx1) + abs(Y[i] - sy1),
d[i << 1 | 1] = abs(X[i] - sx2) + abs(Y[i] - sy2);
for (int i = 1; i <= A; i++)
scanf("%d%d", &hate[i][0], &hate[i][1]);
for (int i = 1; i <= B; i++)
scanf("%d%d", &like[i][0], &like[i][1]);
int l = 0, r = 8000000, m, ans = -1;
while (l <= r)
check(m = (l + r) >> 1) ? r = (ans = m) - 1 : l = m + 1;
printf("%d\n", ans);
return 0;
}

@ -0,0 +1,65 @@
#include <cstdio>
#include <cstring>
inline int min(int a, int b) { return a < b ? a : b; }
const int maxn = 2010, maxm = 500010;
int head[maxn], next[maxm], to[maxm], ecnt;
inline void addEdge(int f, int t)
{
next[ecnt] = head[f];
head[f] = ecnt;
to[ecnt] = t;
ecnt++;
}
int dfn[maxn], low[maxn], stk[maxn], scc[maxn], top, idx, scccnt;
void tarjan(int x)
{
dfn[x] = low[x] = ++idx;
stk[top++] = x;
for (int i = head[x]; ~i; i = next[i])
if (!dfn[to[i]])
tarjan(to[i]), low[x] = min(low[x], low[to[i]]);
else if (!scc[to[i]])
low[x] = min(low[x], dfn[to[i]]);
if (dfn[x] == low[x])
{
scccnt++;
do
scc[stk[--top]] = scccnt;
while (stk[top] != x);
}
}
int main()
{
int m, n;
while (scanf("%d%d", &n, &m) && (m + n))
{
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(scc, 0, sizeof(scc));
idx = top = ecnt = scccnt = 0;
int a1, a2;
char c1, c2;
for (int i = 0; i < m; i++)
{
scanf("%d%c %d%c", &a1, &c1, &a2, &c2);
a1 = a1 << 1 | (c1 == 'h'), a2 = a2 << 1 | (c2 == 'h');
addEdge(a1, a2 ^ 1), addEdge(a2, a1 ^ 1);
}
addEdge(0, 1);
for (int i = 0; i < (n << 1); i++)
if (!dfn[i]) tarjan(i);
bool flag = true;
for (int i = 0; i < n && flag; i++)
if (scc[i << 1] == scc[i << 1 | 1])
flag = false;
if (!flag)
puts("bad luck");
else if (n < 1)
putchar('\n');
else
for (int i = 1; i < n; i++)
printf("%d%c%c", i, (scc[i << 1] > scc[i << 1 | 1]) ? 'w' : 'h', " \n"[i == n - 1]);
}
return 0;
}

@ -0,0 +1,88 @@
#include <cstdio>
#include <cstring>
inline int min(int a, int b) { return a < b ? a : b; }
const int maxn = 10010, maxm = 4000010;
int head[maxn], next[maxm], to[maxm], ecnt;
inline void addEdge(int f, int t)
{
next[ecnt] = head[f];
head[f] = ecnt;
to[ecnt] = t;
ecnt++;
}
int dfn[maxn], low[maxn], stk[maxn], scc[maxn], top, idx, scccnt;
void tarjan(int x)
{
dfn[x] = low[x] = ++idx;
stk[top++] = x;
for (int i = head[x]; ~i; i = next[i])
if (!dfn[to[i]])
tarjan(to[i]), low[x] = min(low[x], low[to[i]]);
else if (!scc[to[i]])
low[x] = min(low[x], dfn[to[i]]);
if (dfn[x] == low[x])
{
scccnt++;
do
scc[stk[--top]] = scccnt;
while (stk[top] != x);
}
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m))
{
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(scc, 0, sizeof(scc));
memset(head, -1, sizeof(head));
ecnt = top = idx = scccnt = 0;
for (int i = 0, u, v, w; i < m; ++i)
{
char op[5];
scanf("%d%d%d%s", &u, &v, &w, op);
if (op[0] == 'A')
if (w)
{
addEdge(u << 1, v << 1 | 1), addEdge(v << 1, u << 1 | 1);
addEdge(u << 1, v << 1), addEdge(v << 1 | 1, u << 1 | 1);
addEdge(u << 1 | 1, v << 1 | 1), addEdge(v << 1, u << 1);
}
else
{
addEdge(u << 1 | 1, v << 1), addEdge(v << 1 | 1, u << 1);
}
if (op[0] == 'O')
if (w)
{
addEdge(u << 1, v << 1 | 1), addEdge(v << 1, u << 1 | 1);
}
else
{
addEdge(u << 1, v << 1), addEdge(v << 1 | 1, u << 1 | 1);
addEdge(u << 1 | 1, v << 1 | 1), addEdge(v << 1, u << 1);
addEdge(u << 1 | 1, v << 1), addEdge(v << 1 | 1, u << 1);
}
if (op[0] == 'X')
if (w)
{
addEdge(u << 1, v << 1 | 1), addEdge(v << 1, u << 1 | 1);
addEdge(u << 1 | 1, v << 1), addEdge(v << 1 | 1, u << 1);
}
else
{
addEdge(u << 1, v << 1), addEdge(v << 1 | 1, u << 1 | 1);
addEdge(u << 1 | 1, v << 1 | 1), addEdge(v << 1, u << 1);
}
}
for (int i = 0; i < (n << 1); i++)
if (!dfn[i]) tarjan(i);
bool flag = true;
for (int i = 0; i < n && flag; i++)
if (scc[i << 1] == scc[i << 1 | 1])
flag = false;
puts(flag ? "YES" : "NO");
}
return 0;
}

@ -63,4 +63,25 @@
\subparagraph{\href{http://poj.org/problem?id=1523}{POJ1523} - SPF}
求割点与删除这个点之后有多少个连通分量
\codeinput[Redundant Paths]{assets/day1/poj1523.cpp}
\subsection{2-SAT}
\paragraph{定义}
给定一个布尔方程,判断是否存在一组布尔变量的取值方案,使得整个方程值为真的问题,被称为布尔方程的可满足性问题(SAT)。SAT问题是NP完全的但对于一些特殊形式的SAT问题我们可以有效求解。\\
我们将下面这种布尔方程称为合取范式:
$$(a\lor b\lor c\lor\cdots)\land(d\lor e\lor f\lor\cdots)\land\cdots$$
其中$a,b,c,\cdots$称为文字,它是一个布尔变量或其否定。像$(a\lor b\lor c\lor\cdots)$这样用$\lor$连接的部分称为子句。如果合取范式的每个子句中的文字个数都不超过两个那么对应的SAT问题又称为\textbf{2-SAT}问题。
\paragraph{解法}
对于给定的\textbf{2-SAT}问题,首先利用$\Rightarrow$将每个子句$(a\lor b)$改写成等价形式$(\neg a\Rightarrow b\land a\Rightarrow\neg b)$.这样原布尔公式就变成了把$a\Rightarrow b$形式的布尔公式用$\land$连接起来的形式。\\
对每个布尔变量$x$构造两个顶点分别代表$x$$\neg x$。以$\Rightarrow$关系为边建立有向图。若在此图中$a$点能到达$b$点,就表示$a$为真时$b$也一定为真。因此该图中同一个强连通分量中所含的所有变量的布尔值均相同。\\
若存在某个变量$x$,代表$x$$\neg x$的两个顶点在同一个强连通分量中,则原布尔表达式的值无法为真。\\
反之若不存在这样的变量,那么我们先将原图中所有的强连通分量缩为一个点,构出一个新图,新图显然是一个拓扑图,我们求出它的一个拓扑序。那么对于每个变量$x$\textbf{$$x\text{所在的强连通分量(新图中的点)的拓扑序在}\neg x\text{所在的强连通分量之后}\Leftrightarrow x\text{为真}$$}就是一组合适布尔变量赋值。注意到 Tarjan 算法所求的强连通分量就是按拓扑序的逆序得出的,因此不需要真的缩点建新图求拓扑序,直接利用强连通分量的编号来当做顺序即可。
\paragraph{练习题}
\subparagraph{\href{http://poj.org/problem?id=3648}{POJ3648} - Wedding}
Additionally, there are several pairs of people conducting adulterous relationships (both different-sex and same-sex relationships are possible)
\codeinput[adulterous relationships]{assets/day1/poj3648.cpp}
\subparagraph{\href{http://poj.org/problem?id=3678}{POJ3678} - Katu Puzzle}
我什么时候做过这个题?
\codeinput[Katu Puzzle]{assets/day1/poj3678.cpp}
\subparagraph{\href{http://poj.org/problem?id=2749}{POJ2749} - Building roads}
杀光奶牛问题就会得到解决
\codeinput[Building roads]{assets/day1/poj2749.cpp}
\end{document}
Loading…
Cancel
Save