A
Knights of the Round Table |
模型:
给出一张图(|V| <= 1000),求所有包含在奇数环中的点。
算法分析:
对每一个连通的子图,找出图中的割点,然后这些割点可以将图分为几部分,对于每一部分,每个点都至少在一个环中,
因此如果该部分存在一个奇数环,则该部分所有点都属于一个奇数环。
对于某一个图中是否存在奇数环的问题,只需黑白染色判断是否是二分图即可~
复杂度|V| + |E|。
注意那些度数<=1的点,我的实现方法需要预先删除这些点。

CODE
1
// Central Europe 2005, Knights of the Round Table
2
// Written By FreePeter
3
4
#include <cstdio>
5
#include <cstring>
6
#include <iostream>
7
#include <algorithm>
8
#include <queue>
9
10
using namespace std;
11
12
const int MaxN = 1000 + 10;
13
bool g[MaxN][MaxN], conv[MaxN], vis[MaxN], ins[MaxN];
14
int n, m, dfs_time[MaxN], d_t, color[MaxN], low[MaxN];
15
bool bad[MaxN];
16
int deg[MaxN];
17
18
19
void init();
20
void work();
21
void dfs_c(int u, int fa, int r);
22
bool dfs_w(int u, int c);
23
void dfs_get(int u);
24
25
int main()
{
26
for (; ;)
{
27
scanf("%d%d", &n, &m);
28
if (n == 0 && m == 0) break;
29
init();
30
work();
31
}
32
return 0;
33
}
34
35
void init()
{
36
fill(g[0], g[MaxN], true);
37
for (int i = 0; i < n; ++i) g[i][i] = false;
38
for (; m > 0; --m)
{
39
int a, b;
40
scanf("%d%d", &a, &b); --a; --b;
41
g[a][b] = false; g[b][a] = false;
42
}
43
44
fill(bad, bad + n, false);
45
queue<int> q;
46
for (int i = 0; i < n; ++i)
{
47
int cnt = 0;
48
for (int j = 0; j < n; ++j)
49
if (g[i][j]) ++cnt;
50
deg[i] = cnt;
51
if (deg[i] <= 1)
{
52
q.push(i); bad[i] = true;
53
}
54
}
55
56
for (; !q.empty(); q.pop())
{
57
int u = q.front();
58
for (int i = 0; i < n; ++i)
59
if (g[u][i] && !bad[i])
{
60
if (--deg[i] <= 1)
{
61
q.push(i); bad[i] = true;
62
}
63
}
64
}
65
66
}
67
68
void work()
{
69
fill(conv, conv + MaxN, false);
70
fill(vis, vis + MaxN, false);
71
d_t = 0;
72
for (int i = 0; i < n; ++i)
{
73
if (bad[i]) continue;
74
if (!vis[i]) dfs_c(i, -1, i);
75
}
76
77
fill(color, color + MaxN, 0);
78
bool mark[MaxN];
79
fill(mark, mark + MaxN, false);
80
fill(vis, vis + MaxN, false);
81
int c = 10;
82
for (int i = 0; i < n; ++i)
{
83
if (bad[i]) continue;
84
if (!conv[i] && !vis[i])
{
85
fill(ins, ins + MaxN, false);
86
dfs_get(i);
87
if (!dfs_w(i, c))
88
for (int j = 0; j < n; ++j)
{
89
if (bad[i]) continue;
90
if (ins[j]) mark[j] = true;
91
}
92
c++;
93
}
94
}
95
96
int ans = 0;
97
for (int i = 0; i < n; ++i) if (mark[i]) ++ans;
98
cout << n - ans << endl;
99
}
100
101
void dfs_c(int u, int fa, int r)
{
102
bool first = true;
103
dfs_time[u] = d_t++; low[u] = dfs_time[u]; vis[u] = true;
104
for (int i = 0; i < n; ++i)
105
if (g[u][i] && i != fa)
{
106
if (bad[i]) continue;
107
108
if (!vis[i])
{
109
if (u == r && !first) conv[u] = true;
110
first = false;
111
dfs_c(i, u, r);
112
low[u] = min(low[u], low[i]);
113
if (low[i] >= dfs_time[u] && u != r) conv[u] = true;
114
}
115
else if (vis[i] && dfs_time[i] < dfs_time[u]) low[u] = min(low[u], dfs_time[i]);
116
}
117
}
118
119
bool dfs_w(int u, int c)
{
120
color[u] = c;
121
for (int i = 0; i < n; ++i)
{
122
if (bad[i]) continue;
123
124
if (g[u][i] && ins[i])
125
if (abs(color[i]) != c)
{
126
if (!dfs_w(i, -c)) return false;
127
}
128
else if (color[i] != -c) return false;
129
}
130
return true;
131
}
132
133
void dfs_get(int u)
{
134
ins[u] = true; vis[u] = true;
135
if (conv[u]) return;
136
for (int i = 0; i < n; ++i)
{
137
if (bad[i]) continue;
138
139
if (g[u][i] && !ins[i]) dfs_get(i);
140
}
141
}
142
B
|
The Cow Doctor |
模型:
给出m个集合,里面存在n种元素。求这些集合中可以被其他集合并得到的(精确相等)。
m <= 200, n <= 300
算法分析:
设A能被其他集合B1, B2, ... Bi并得到,则B1, B2, ... Bi显然都属于A。
因此,我们可以找出所有属于A的集合B1, B2, ... Bi,求它们的并,看是否等于A。
复杂度O(m ^ 2 * n),具体实现可以使用bitset :)
C
Wild West模型:
给出n个长方体(0, 0, 0) - (ai, bi, ci),求它们并的总体积。
n, a, b, c <= 100000
算法分析:
首先想到用一个平行于xy的平面去截这些长方体。方便起见我们从最大的c开始截。
注意到保证所有长方体必定是以(0, 0, 0)点作为一个顶点的,所以平面向下移动的过程中截到的内容只增不减。
剩下的核心问题就是维护对长方形序列(0, 0) - (ai, bi)并动态报告它们的面积并。
注意到必定以(0, 0)为一个节点,所以我们每行只需要记录延伸的长度。
用线段树维护并且报告面积即可。
复杂度O(nlogn)
D
Pixel Shuffle算出目标置换,然后算出每个cycle的长度,求LCM~
Ural1024 Permutations 是一道单纯计算置换多少次可以回到原始的题。
ms就是Europe - Southwestern - 2005/2006的Pixel Shuffle,寒,欧洲人出题抄来抄去的。
uva3510
E
Find the Clones弱题,排序再扫描。
F
The Warehouse算法分析:
显然是搜索。不过似乎官方数据不会太强,如下的数据比赛的时候AC的程序就跑不出来。
8 6 1E...2.............222222................22222222..........2..2..我用BFS + SET做的。似乎还可以DFS + 剪枝。

CODE
1
// Central Europe 2005, The Warehouse
2
// Written By FreePeter
3
4
#include <cstdio>
5
#include <cstring>
6
#include <iostream>
7
#include <algorithm>
8
#include <set>
9
10
using namespace std;
11
12
const int MaxQ = 100000, dx[4] =
{-1, 0, 0, 1}, dy[4] =
{0, -1, 1, 0};
13
struct queuenode
14

{
15
int data[8][8], x, y;
16
}queue[MaxQ];
17
int n, sx, sy, fx, fy, init_st[8][8];
18
set<queuenode> exist;
19
20
void init();
21
void bfs();
22
bool operator<(const queuenode& a, const queuenode& b);
23
24
int main()
25

{
26
while (true)
27
{
28
scanf("%d%d%d", &n, &sx, &sy);
29
if (n == 0 && sx == 0 && sy == 0) break;
30
init();
31
bfs();
32
}
33
return 0;
34
}
35
36
void init()
37

{
38
for (int i = 0; i < n; ++i)
39
{
40
char tmp[10];
41
scanf("%s", tmp);
42
for (int j = 0; j < n; ++j)
43
{
44