并查集解决的是连通性(无向图联通分量)和传递性(家谱关系)问题,并且可以动态的维护。抛开格子不看,任意一个图中,增加一条边形成环当且仅当这条边连接的两点已经联通,于是可以将点分为若干个集合,每个集合对应图中的一个连通块。
#include
using namespace std;
const int N = 500007;
int n, m;
int fa[N];
bool flag;
int get(int x, int y){
return x * n + y;
}
int find(int x){
if(fa[x] == x)return x;
return fa[x] = find(fa[x]);
}
int main(){
scanf("%d%d", &n, &m);
int res;
for(int i = 1;i <= n * n ; ++ i)
fa[i] = i;
for(int i = 1;i <= m; ++ i){
int x, y, a, b;
char op[2];
scanf("%d%d%s", &x, &y, op);
x -- , y -- ;
a = get(x, y);
if(*op == 'D')
b = get(x + 1, y);
else b = get(x, y + 1);
int aa = find(a), bb = find(b);
if(aa == bb && !flag){
res = i;
flag = true;
}
fa[aa] = bb;
}
if(res)
printf("%d\n", res);
else puts("draw");
return 0;
}
并查集缩点+01背包
可以利用并查集,将这m组配对购买的商品划到一个集合里,这样就可以确定买了其中一个就得买另一个。
//并查集没有办法通过一个点直接找到所有的该集合的点,但是这里我们可以O(n)把属于同一个集合的点缩点,缩成一个物品然后裸一个01背包
#include
#include
#include
using namespace std;
const int N = 50007;
int n, m, k;
int fa[N];
int a[N], b[N];
int c[N], w[N];
int f[N];
int find(int x){
if(x == fa[x])return x;
return fa[x] = find(fa[x]);
}
int main(){
scanf("%d%d%d", &n, &m, &k);
for(int i = 1;i <= n; ++ i)scanf("%d%d", &c[i], &w[i]);
for(int i = 1;i <= n; ++ i)
fa[i] = i;
for(int i = 1;i <= m; ++ i){
int x, y;
scanf("%d%d", &x, &y);
int fx = find(x), fy = find(y);
if(fx != fy){
fa[fx] = fy;
c[fy] += c[fx];
w[fy] += w[fx];
}
}
for(int i = 1;i <= n; ++ i)
for(int j = k; j >= c[i]; -- j){
if(fa[i] == i)
f[j] = max(f[j], f[j - c[i]] + w[i]);
}
printf("%d\n", f[k]);
return 0;
}
也可以用tarjan缩点+背包
#include
using namespace std;
const int maxn=10000+5;
int money[maxn],fa[maxn];
int c[maxn],d[maxn];
int head[maxn],next[maxn],to[maxn],cnt=0;
int add(int x,int y)
{
to[++cnt]=y;
next[cnt]=head[x];
head[x]=cnt;
}
int dfn[maxn],low[maxn],sum=0;
int st[maxn],top=0;
int col=0,co[maxn];
int a[maxn],b[maxn];
int dp[maxn];
void tarjan(int node)
{
dfn[node]=low[node]=++sum;
st[++top]=node;
for(int i=head[node];i;i=next[i])
{
int y=to[i];
if(!dfn[y])
{
tarjan(y);
low[node]=min(low[node],dfn[y]);
}
if(!co[y])
{
low[node]=min(low[node],low[y]);
}
}
if(dfn[node]==low[node])
{
col++;
while(st[top]!=node)
{
a[col]+=c[st[top]];
b[col]+=d[st[top]];
co[st[top]]=col;
top--;
}
a[col]+=c[st[top]];
b[col]+=d[st[top]];
co[st[top]]=col;
top--;
}
}
int main()
{
int n,m,s;
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&c[i],&d[i]);
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(int i=1;i<=col;i++)
{
for(int j=s;j>=a[i];j--)
{
dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
}
}
printf("%d\n",dp[s]);
return 0;
}