Abstract
Codeforces 105D
并查集(官方标的)
Body
Source
http://codeforces.com/problemset/problem/105/D
Description
题意很复杂,自己看……我一开始也没看懂,把那个gif动态图看个10遍以上就懂了。
http://212.193.37.254/codeforces/images/geo_slow.gif
Solution
比较裸的并查集。注意到染色操作实际上就是将原本颜色不同的格子合并到一起即可。计算螺旋形距离的话,实际上只跟格子相对中心格的坐标有关。我是直接找公式,CF上面的代码好像大部分是直接记录,各种step++什么的,看不懂。
但是仔细分析后我觉得,其实和并查集没有什么关系……令当前需要染色的格子集合为S。可以证明,实际上每次染色只会把别的格子并入S,而不会从S中删除或换掉格子(尽管S的颜色不断改变)。于是只用记录S的颜色和大小即可。
P.S. 写得这么简陋还叫解题报告实在是太不好意思了,以后标签改成[代码]好了。
Code
并查集(我写的并查集很长很难看,大家还是看CF上面的代码好了)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <queue>
#include <map>
using namespace std;
const int S = 303*303*2;
typedef long long LL;
typedef pair<int, int> pr;
pr (*mkpr)(int, int)=make_pair;
int N, M;
LL ans = 0;
map<int, int> color;
int f[S], r[S], c[S], s[S];
int pan[303][303], sym[303][303];
int colorcnt = 0;
vector<pr> node[S];
queue<pr> q;
pr now;
int cnow, cchg;
inline int getcolor(int x)
{
if (!color.count(x)) color[x] = colorcnt++;
return color[x];
}
inline int dis(int i, int j)
{
int n;
if (j <= 0) n = max(abs(j), abs(i)-1);
else n = max(abs(j), abs(i))-1;
if (i==n+1) return 4*(n+1)*(n+1)+(n+1)-j;
else if (j==n+1) return (4*n+2)*(n+1)+(n+1)+i;
else if (i==-n-1) return (2*n+1)*(2*n+1)+n+j;
else return 4*n*n+2*n+n-i;
}
bool cmp(const pr &u, const pr &v)
{return dis(u.first-now.first, u.second-now.second)<dis(v.first-now.first, v.second-now.second);}
int find(int x)
{
if (f[x]==x) return x;
return f[x] = find(f[x]);
}
int join(int u, int v)
{
int ru = find(u), rv = find(v);
if (ru == rv) return ru;
if (r[ru]<r[rv])
{
s[rv] += s[ru];
s[ru] = 0;
return f[ru] = rv;
}
else if (r[rv]<r[ru])
{
s[ru] += s[rv];
s[rv] = 0;
return f[rv] = ru;
}
else
{
r[rv]++;
s[rv] += s[ru];
s[ru] = 0;
return f[ru] = rv;
}
}
void init()
{
for (int i = 0; i < colorcnt; ++i)
{
f[i] = i;
c[i] = i;
r[i] = 0;
}
}
int main()
{
int i, j, k, x, y, root;
scanf("%d%d", &N, &M);
color[0] = colorcnt++;
for (i = 0; i < N; ++i)
for (j = 0; j < M; ++j)
{
scanf("%d", &pan[i][j]);
pan[i][j] = getcolor(pan[i][j]);
s[pan[i][j]]++;
}
for (i = 0; i < N; ++i)
for (j = 0; j < M; ++j)
{
scanf("%d", &sym[i][j]);
if (sym[i][j]!=-1) sym[i][j] = getcolor(sym[i][j]);
}
init();
scanf("%d%d", &x, &y);
x--; y--;
for (i = 0; i < N; ++i)
for (j = 0; j < M; ++j)
if (i==x&&j==y) q.push(mkpr(i, j));
else if (sym[i][j]!=-1) node[pan[i][j]].push_back(mkpr(i, j));
while (!q.empty())
{
now = q.front(); q.pop();
i = now.first, j = now.second;
root = find(pan[i][j]);
cnow = c[root]; cchg = sym[i][j];
if (cnow==0 || cnow==cchg) continue;
ans += s[root];
vector<pr> elm = node[cnow];
node[cnow].clear();
sort(elm.begin(), elm.end(), cmp);
for (k = 0; k < elm.size(); ++k)
q.push(elm[k]);
f[cchg] = cchg;
c[join(root, cchg)] = cchg;
}
cout << ans << endl;
}
非并查集
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <queue>
#include <map>
using namespace std;
const int S = 303*303*2;
typedef long long LL;
typedef pair<int, int> pr;
pr (*mkpr)(int, int)=make_pair;
int N, M;
LL ans = 0;
map<int, int> color;
int s[S];
int pan[303][303], sym[303][303];
int colorcnt = 0;
vector<pr> node[S];
queue<pr> q;
pr now;
int snow, cnow, cchg;
inline int getcolor(int x)
{
if (!color.count(x)) color[x] = colorcnt++;
return color[x];
}
inline int dis(int i, int j)
{
int n;
if (j <= 0) n = max(abs(j), abs(i)-1);
else n = max(abs(j), abs(i))-1;
if (i==n+1) return 4*(n+1)*(n+1)+(n+1)-j;
else if (j==n+1) return (4*n+2)*(n+1)+(n+1)+i;
else if (i==-n-1) return (2*n+1)*(2*n+1)+n+j;
else return 4*n*n+2*n+n-i;
}
bool cmp(const pr &u, const pr &v)
{return dis(u.first-now.first, u.second-now.second)<dis(v.first-now.first, v.second-now.second);}
int main()
{
int i, j, k, x, y;
scanf("%d%d", &N, &M);
color[0] = colorcnt++;
for (i = 0; i < N; ++i)
for (j = 0; j < M; ++j)
{
scanf("%d", &pan[i][j]);
pan[i][j] = getcolor(pan[i][j]);
s[pan[i][j]]++;
}
for (i = 0; i < N; ++i)
for (j = 0; j < M; ++j)
{
scanf("%d", &sym[i][j]);
if (sym[i][j]!=-1) sym[i][j] = getcolor(sym[i][j]);
}
scanf("%d%d", &x, &y);
x--; y--;
for (i = 0; i < N; ++i)
for (j = 0; j < M; ++j)
if (i==x&&j==y) q.push(mkpr(i, j));
else if (sym[i][j]!=-1) node[pan[i][j]].push_back(mkpr(i, j));
cnow = pan[x][y]; snow = 0;
while (!q.empty())
{
now = q.front(); q.pop();
i = now.first, j = now.second;
cchg = sym[i][j];
if (cnow==0 || cnow==cchg) continue;
snow += s[cnow];
s[cnow] = 0;
ans += snow;
vector<pr> elm = node[cnow];
node[cnow].clear();
sort(elm.begin(), elm.end(), cmp);
for (k = 0; k < elm.size(); ++k)
q.push(elm[k]);
cnow = cchg;
}
cout << ans << endl;
}