P7991 [USACO21DEC] Connecting Two Barns S
好像没有人用 dfs 判连通块,我来水一发。
思路、实现
通过 dfs 把连通块当作新图结点并储存。
此时一共有三种情况。
第一种是 $1$ 和 $n$ 之间已经连通,不需要进行操作。
第二种是需要进行连接一次来达到题目要求。
第三种是需要进行连接两次来达到题目要求。
上述三种情况的最小价值即为最终答案,分类讨论即可。
(这是 dfs 部分代码)
bool vis[MAXN];
void dfs(int x)
{
G2[tot].push_back(x);
vis[x]=true;
for(int i=0;i<G[x].size();i++)
{
int y=G[x][i];
if(vis[y])continue;
dfs(y);
}
}
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=2e5+10;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,m,tot;//tot 为连通块计数器
ll ans;
vector<int>G[MAXN],G2[MAXN];//G2 为新图
bool vis[MAXN];
void dfs(int x)
{
G2[tot].push_back(x);
vis[x]=true;
for(int i=0;i<G[x].size();i++)
{
int y=G[x][i];
if(vis[y])continue;
dfs(y);
}
}
ll calc(int x,int y)
{
ll cnt=INF;
if(G2[x].size()>G2[y].size())swap(x,y);
int l=G2[y].size();
for(int i=0;i<G2[x].size();i++)
{
int u=G2[x][i];
int pos=lower_bound(G2[y].begin(),G2[y].end(),u)-G2[y].begin();
int v1=G2[y][min(pos,l-1)],v2=G2[y][max(0,pos-1)];
cnt=min(cnt,(ll)(v1-u)*(v1-u));
cnt=min(cnt,(ll)(v2-u)*(v2-u));
}
return cnt;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
tot=0;
ans=INF;
for(int i=1;i<=n;i++)
{
G[i].clear();
G2[i].clear();
}
memset(vis,0,sizeof(vis));//以上为初始化
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
tot++;
dfs(1);
tot++;
dfs(n);
for(int i=1;i<=n;i++)
{
if(vis[i])continue;
tot++;
dfs(i);
}
for(int i=1;i<=tot;i++)sort(G2[i].begin(),G2[i].end());//这里用 set 代替 vector 也可实现排序
ans=min(ans,calc(1,2));
for(int i=3;i<=tot;i++)ans=min(ans,calc(1,i)+calc(2,i));
cout<<ans<<'\n';
}
return 0;
}
P.s.:没人试试 Tarjan 判连通块吗 qwq

浙公网安备 33010602011771号