图联通问题——洛谷P2978
【问题描述】
给定一个无向图,有n个顶点和m条边。
并给定Q次查询,每次给定起点st和终点ed,请判断st和ed是否联通
【输入格式】
第一行有2个数字n、m,用空格隔开,表示有n个顶点,m条边
接下来有m行,每行两个数字u和v,表示一条无向边(u,v)
接下来有Q行,每行两个数字st和ed,用空格隔开,表示起点和终点
【输出格式】
Q行,每行一个数字1或者0,1表示st和ed连通,0表示不连通
【数据范围】
1<=n,m,Q,st,ed<=100
【输入样例1】
5 3
1 2
1 3
4 5
2
2 3
2 4
【输出样例1】
1
0
【输入样例2】
5 4
1 2
5 2
3 4
2 4
2
4 5
3 2
【输出样例2】
1
1
解法1. DFS写法1
int main() {
cin>>n>>m;
int Q;
cin>>Q;
vector<vector<int> > adj_t(n+1,vector<int>());
for(int i=0;i<m;i++){
int u,v;
cin>>u>>v;
adj_t[u].push_back(v);
adj_t[v].push_back(u);
}
adjList=adj_t;
vector<bool> vis_t(n+1,false);
vis=vis_t;
while(Q--){
int st,end;
cin>>st>>end;
if(dfs(st,end)){
cout<<"Y"<<endl;
}else{
cout<<"N"<<endl;
}
fill(vis.begin(),vis.end(),false);
}
return 0;
}
解法2. DFS写法2
int main() {
cin>>n>>m;
int Q;
cin>>Q;
vector<vector<int> > adj_t(n+1,vector<int>());
for(int i=0;i<m;i++){
int u,v;
cin>>u>>v;
adj_t[u].push_back(v);adj_t[v].push_back(u);
}
adjList=adj_t;
vector<int> vis_t(n+1,false);
vis=vis_t;
for(int i=1;i<=n;i++){
if(!vis[i]){
vis[i]=i;
dfs(i);
}
}
while(Q--){
int st,end;
cin>>st>>end;
if(vis[st]==vis[end]){
cout<<"Y"<<endl;
}else{
cout<<"N"<<endl;
}
}
return 0;
}
解法3. BFS
int main() {
int x,y;
cin>>n>>m>>Q;
for(int i=1;i<=m;i++){
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
while(Q--){
//重置
memset(vis,0,sizeof(vis));
//清空队列
queue<int> q_temp;
q=q_temp;
cin>>st>>ed;
//调用广搜函数
bool rst=bfs();
//输出结果
if(rst){
cout<<"Y"<<endl;
}else{
cout<<"N"<<endl;
}
}
return 0;
}
解法4. Floyd传递闭包
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define endl '\n'
bool dp[1001][1001];
//n个顶点,m条边
int n,m,st,ed,Q;
void floyed(){
for(int k = 1; k <=n; k++) {
for(int i = 1; i <=n; i++) {
for(int j = 1; j <= n; j++) {
dp[i][j] = dp[i][j]||(dp[i][k]&&dp[k][j]);
}
}
}
}
int main() {
cin >> n >> m>>Q;
memset(dp,false,sizeof(dp));
for(int i = 1; i <=m; i++) {
int p,q;
cin >> p >> q;
dp[p][q]=dp[q][p] = true;
}
floyed();
while(Q--){
cin>>st>>ed;
if(dp[st][ed]){
cout<<'Y'<<endl;
}else{
cout<<'N'<<endl;
}
}
return 0;
}
解法5. 并查集
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
#define endl '\n'
int n,m;
vector<int> uf;
int _find(int p){
if(!uf[p]){
return p;
}else{
int root=_find(uf[p]);
uf[p]=root;
return root;
}
}
void un(int p,int q){
int root1=_find(p),root2=_find(q);
if(root1!=root2){
uf[root1]=root2;
}
}
int main() {
cin>>n>>m;
int Q;cin>>Q;
vector<int> uf_t(n+1,0);
uf=uf_t;
for(int i=0;i<m;i++){
int u,v;cin>>u>>v;
un(u,v);
}
while(Q--){
int i,j;cin>>i>>j;
if(_find(i)==_find(j)){
cout<<"Y"<<endl;
}else cout<<"N"<<endl;
}
return 0;
}
练习2
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int N = 1100;
int a, b, n, m, x, y;
vector<int> g[N];
int vis[N];
void dfs(int x) {
vis[x] = true;
for (unsigned i = 0; i < g[x].size(); i++) {
int v = g[x][i];
if (vis[v])
continue;
dfs(v);
}
}
练习3:最长路
解法1.DFS
#include <vector>
#include <iostream>
using namespace std;
const int INF=0x6ffffff;
int dis[500001]; //距离记录
int n, m;
struct node {
int x, y;
};
vector<node> G[500001];
void dfs(int x, int s);
int main() {
cin >> n >> m;
int u, v, w;
for (int i = 1; i <= m; i++) {
cin >> u >> v >> w;
G[u].push_back( { v, w });
}
fill(dis,dis+n+1,-INF);
dfs(1, 0);
if (dis[n]==-INF)
cout << -1;
else
cout << dis[n];
return 0;
}
解法2. SPFA
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
typedef long long LONG;
using namespace std;
const int MaxN=10001;
LONG INF=6553500;
vector<pair<int,LONG> > adjs[MaxN];
LONG dp[MaxN];
int N,M,ans;
bool vis[MaxN];
//是否可以从p到达写死的target
bool canGo(int p,int& target){
if(p==target){
return true;
}else{
for(unsigned i=0;i<adjs[p].size();i++){
int v=adjs[p][i].first;
if(!vis[v]){
bool f=canGo(v,target);
if(f){
return true;
}
}
}
return false;
}
}
void spfa(){
memset(vis,0,sizeof(vis));
fill(dp,dp+N+1,-INF);
queue<int> que;
que.push(1);
vis[1]=true;
dp[1]=0;
while(!que.empty()){
int p=que.front();
que.pop();
vis[p]=0;
for(unsigned i=0;i<adjs[p].size();i++){
int v=adjs[p][i].first;
if(dp[p]+adjs[p][i].second>dp[v]){
dp[v]=dp[p]+adjs[p][i].second;
if(!vis[v]){
que.push(v);
vis[v]=1;
}
}
}
}
if (dp[N]==-INF)
cout << -1;
else
cout << dp[N];
}
int main() {
INF*=INF;
cin>>N>>M;
for(int i=1;i<=M;i++){
int u, v;LONG len;
cin >> u >> v >> len;
adjs[u].push_back(make_pair(v,len));
}
if(!canGo(1,N)){
cout<<-1<<endl;
return 0;
}
fill(dp,dp+N+1,-INF);
spfa();
return 0;
}
练习4:迷宫BFS
#include <iostream>
#include <queue>
#include <string>
using namespace std;
const int N = 1e3 + 7;
int dir[8][2] = {{2,1},{-2,-1},{2,-1},{1,-2},{1, 2},{-1, 2},{-2, 1}, {-1,-2}};
int n, m,sx,sy,ex,ey, dis[N][N], vis[N][N];
string s[N];
struct node{
int x, y;
};
int bfs(int sx, int sy);
int main(){
cin >> m >> n;
for(int i = 0; i < n; i++) cin >> s[i];
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++){
if(s[i][j] == 'K') sx = i, sy = j;
}
cout << bfs(sx, sy);
return 0;
}
inline bool check(int xx,int yy){
return xx>=0&&xx<n&&yy>=0&&yy<m;
}
练习5. 细胞
#include <iostream>
using namespace std;
const int N = 110;
char a[N][N];
int vis[N][N];
int n, m;
int dx[4] = { 0, 1, 0, -1 };
int dy[4] = { 1, 0, -1, 0 };
bool check(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
void bfs(int x, int y) {
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> a[i];
int ans = 0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(!vis[i][j]&&a[i][j]!='0'){
bfs(i,j);
ans++;
}
}
}
cout << ans << endl;
return 0;
}
练习6. 联通块数量(八方向)
#include <iostream>
#include <queue>
using namespace std;
char a[112][112];
int n, m, vis[112][112], ans = 0;
int dx[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
int dy[] = { 0, 1, 1, 1, 0, -1, -1, -1 };
struct node {
int x, y;
};
void bfs(int x, int y);
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
cin >> a[i][j];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (!vis[i][j] && a[i][j] == 'W') {
bfs(i, j);
ans++;
}
}
}
cout << ans;
return 0;
}
bool check(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m;
}
练习7
比赛T5








