1.P3367 【模板】并查集
并 + 查
详见注释
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e4+5;
int f[MAX_N];
int father(int x)//查找根节点
{
if(f[x] != x)
f[x] = father(f[x]);
return f[x];
}
void connect(int a,int b)//合并两个集合
{
int roota = father(a);
int rootb = father(b);
if(roota != rootb)
f[roota] = rootb;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
f[i] = i;//初始化父节点为自身
for(int i=1;i<=m;i++){
int z,x,y;
cin>>z>>x>>y;
if(z == 1){
connect(x,y);
}
else{
if(father(x) == father(y))
cout<<'Y'<<endl;
else
cout<<'N'<<endl;
}
}
return 0;
}
2.P8604 [蓝桥杯 2013 国 C] 危险系数
选用DFS
分别记录(1)起点到终点的路径总数 (2)某点在起点到终点的所有路径中的出现次数,
当(1)==(2)时,该点一定是起点和终点之间的关键点。
#include <bits/stdc++.h>
using namespace std;
int n,m;
vector<int> a[1005];//所有与i相连的点
int vis[1005],ans[1005];//ans[]表示点i在起点到终点的所有路径中出现了多少次
int s,e,c,res,sum;//sum:起点到终点的路径总数
void dfs(int df)
{
if(df == e){
sum++;
for(int i=1;i<=c;i++){
ans[i] += vis[i]?1:0;
}
return ;
}
vis[df] = 1;
for(auto to:a[df]){
if(vis[to]) continue;
dfs(to);
}
vis[df] = 0;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
c = max(max(c,u),v);
}
cin>>s>>e;
dfs(s);
for(int i=1;i<=c;i++)
if(ans[i] == sum)
res++;
cout<<res-1;
return 0;
}
3.P1330 封锁阳光大学
染色问题:要使每一条边的两点被染成两种不同的颜色,否则,impossible。
#include <bits/stdc++.h>
using namespace std;
vector<int> g[10010];
int color[10010];
int color2[10010];
int n, m;
bool ok;
int dfs(int i, int s){
if (!ok) return 0;
int sum = s;
color[i] = s;
for (int j = 0; j < g[i].size(); j++){
int v = g[i][j];
if (color[v] == -1){
color[v] = (!s);
sum += dfs(v, !s);
} else if (color[v] == s) {
ok = false;
}
}
return sum;
}
int main(){
cin >> n >> m;
for (int i = 0; i < m; i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
memset(color, -1, sizeof(color));
ok = true;
int ans = 0;
for (int i = 1; i <= n; i++){
if (color[i] == -1){
memcpy(color2, color, sizeof(color));
int a = dfs(i, 0);
memcpy(color, color2, sizeof(color));
int b = dfs(i, 1);
ans += min(a, b);
}
if (!ok) break;
}
if (!ok){
cout << "Impossible" << endl;
} else {
cout << ans << endl;
}
return 0;
}
4.P3916 图的遍历
反向建边(蒟蒻新学的)+ DFS
反向建边:题目要求能到达的编号最大的点,可以反向考虑较大的点能够到达哪些点。
#include <bits/stdc++.h>
using namespace std;
int n,m;
vector<int> arr[1005];//存图
int ans[1005];
void dfs(int x,int y)
{
if(ans[x])
return ;//已经来过
ans[x] = y;
for(int i=0;i<arr[x].size();i++)
dfs(arr[x][i],y);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
arr[v].push_back(u);//有向图反向建边
}
for(int i=n;i>=1;i--)
dfs(i,i);
for(int i=1;i<=n;i++){
cout<<ans[i];
if(i!=n) cout<<' ';
}
return 0;
}
5.P1119 灾后重建
原题指路:P1119 灾后重建 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1119
请看VCR 代码
#include<iostream>
#include<cstdio>
#define N 205
using namespace std;
int n,m;
int a[N];
int f[N][N];//邻接矩阵存边
inline void updata(int k){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[j][k])
f[i][j]=f[j][i]=f[i][k]+f[j][k];//用这个新的更新所有前面的
return;
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
scanf("%d",a+i);//依次输入每一个村庄建立完成时需要的时间
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
f[i][j]=1e9;//初始化为保证它不爆炸范围内的最大值
}
for(int i=0;i<n;i++)
f[i][i]=0;
int s1,s2,s3;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&s1,&s2,&s3);
f[s1][s2]=f[s2][s1]=s3;//初始化边长
}
int q;
cin>>q;
int now=0;
for(int i=1;i<=q;i++){//处理各询问
scanf("%d%d%d",&s1,&s2,&s3);
while(a[now]<=s3&&now<n){
updata(now);//依次更新点,使它可以被用来更新其他的点
now++;
}
if(a[s1]>s3||a[s2]>s3)cout<<-1<<endl;
else {
if(f[s1][s2]==1e9)cout<<-1<<endl;
else cout<<f[s1][s2]<<endl;
}
}
return 0;
}