dfs和bfs都还没搞明白又懵懵懂懂地来写题了
P8604 [蓝桥杯 2013 国 C] 危险系数
题目背景
抗日战争时期,冀中平原的地道战曾发挥重要作用。
题目描述
地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。
我们来定义一个危险系数 DF(x,y):
对于两个站点 x 和 y(x不等于y), 如果能找到一个站点 z,当 z 被敌人破坏后,x 和 y 不连通,那么我们称 zz 为关于 x,yx,y 的关键点。相应的,对于任意一对站点 x 和 y,危险系数 DF(x,y)DF(x,y) 就表示为这两点之间的关键点个数。
本题的任务是:已知网络结构,求两站点之间的危险系数。
输入格式
输入数据第一行包含 2 个整数 n(2≤n≤1000),m(0≤m≤2000),分别代表站点数,通道数。
接下来 m 行,每行两个整数 u,v(1≤u,v≤n,u不等于v) 代表一条通道。
最后 1 行,两个数 u,v代表询问两点之间的危险系数 DF(u,v)。
输出格式
一个整数,如果询问的两点不连通则输出 -1。
输入输出样例
输入 #1
7 6 1 3 2 3 3 4 3 5 4 5 5 6 1 6
输出 #1
2
对于这题,因为是讲过后再写的,就写写听的思路吧
就是对于给出所有的点和道路,我们用vector容器来储存形成一张图,然后再这张图上dfs搜索,对于给出的起点和终点,我们再这张图上dfs找出从起点到终点能有多少种走法,然后对于每个点我们都记录一下,危险点就是每一条路都得走过的点,那就很直白了,如果这个点走过的次数等于起点到终点的道路数量,那就表明每一条路都得经过走过点,走过点就是危险点。
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n,m;
int jl[N];
int sum=0;
int zs[N];
int now,js;
vector<int> G[N];
void dfs(int now){
if(now==js){//当这条路走完的时候结束
sum++;//从起点到终点的方法加一种
for(int i=1;i<=n;i++){
if(jl[i]==1) zs[i]++;//对于这种方法来说,走过的每一个点走记录下来,也就是每个点走过的次数都加一
}
return;
}
for(int i=0;i<G[now].size();i++){
if(jl[G[now][i]]==0){
jl[G[now][i]]=1;
dfs(G[now][i]);
jl[G[now][i]]=0;
}
}
return;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++){//m为边的数量
int x,y;
cin>>x>>y;
G[x].push_back(y);//因为是无向图,所以要两边都存储一次
G[y].push_back(x);
}
int ks;
cin>>ks>>js;
jl[ks]=1;//所以要对起点初始化
dfs(ks);//从起点开始
int ans=-2;//去点起点和终点
for(int i=1;i<=n;i++){//走过的次数等于走的方法,说明每一次走都得经过这个点
if(zs[i]==sum) ans++;
}
cout<<ans;
return 0;
}
P3916 图的遍历
题目描述
给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点。
输入格式
第 1 行 2 个整数 N,M表示点数和边数。
接下来 M 行,每行 2 个整数 Ui,Vi,表示边 (Ui,Vi)。点用 1,2,…,N 编号。
输出格式
一行 N 个整数 A(1),A(2),…,A(N)。
输入输出样例
输入 #1
4 3 1 2 2 4 4 3
输出 #1
4 4 3 4
这题的关键就在于,怎么去思考这题,我一开始是去对每个点进行遍历,然后一个个去比较大小,如果就寄了,看了别人的题解后才豁然开朗:题目用反向建图,然后从大的点开始往小的遍历。因为我们要找到最大的点,那我们反着来,从最大的点开始去找所有能到达它的点,那这些点能到达的最大的点就是这个点。秒啊!
#include <bits/stdc++.h>
using namespace std;
int jl[100005];
vector<int> q[100005];
void dfs(int j,int k){
if(jl[j]) return;//表示这个点走过,那我们就可以
jl[j]=k;//如果这个点没有走过,那就是起点,用它这时候的序号k来记录它,然后去找它能走到的点
for(int i=0;i<q[j].size();i++){
dfs(q[j][i],k);//我不断地dfs,从大到小,由大的地方开始,把走过的地方都jl下来
}
}
int main()
{
int n,m;
cin>>n>>m;//n是点数,m是边数
for(int i=0;i<m;i++){//建立边 看来题解,他们用的是反向建边,确实简单了不少,但是我dfs基础不行,只会按一开始的模板死套
int x,y;
cin>>x>>y;
q[y].push_back(x);//反向建边 一般是以G[u,v]先记着
}
for(int i=n;i>0;i--){//因为是反向建边,所以我们反向dfs
dfs(i,i);//dfs(i,i)第一个i用来dfs里面走点,第二个i用来记录下这个点
}
for(int i=1;i<=n;i++){
cout<<jl[i]<<' ';//用jl数组记录下能到达的最大点
}
return 0;
}
P1330 封锁阳光大学
题目描述
曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。
阳光大学的校园是一张由 nn 个点构成的无向图,nn 个点之间由 mm 条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。
询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。
输入格式
第一行两个正整数,表示节点数和边数。 接下来 mm 行,每行两个整数 u,vu,v,表示点 uu 到点 vv 之间有道路相连。
输出格式
仅一行如果河蟹无法封锁所有道路,则输出 Impossible
,否则输出一个整数,表示最少需要多少只河蟹。
输入输出样例
输入 #1
3 3 1 2 1 3 2 3
输出 #1
Impossible
输入 #2
3 2 1 2 2 3
输出 #2
1
这题我是真的崩溃了,我只知道这是无向图,然后用vector构建了图,然后就不会了,河蟹不能相邻,也就是 01分布一样的,有想法但不多,所有不会写,于是去看了题解,那个上面链式向前星,ok没学,不会,下一个,暴力搜索我喜欢,就它了
#include <bits/stdc++.h>
using namespace std;
vector<int> q[10005];//容器存图 还是彩笔一个
int c[10005],x;
int used[10005];//记录这个点有没有被用过
void dfs(int dian,int bj){
if(c[dian]!=-1&&c[dian]!=bj){//这个点还没走过且要标记的颜色和上个点相同也就是两只河蟹在一起了
cout<<"Impossible";
exit(0);//正常状态退出
}
if(c[dian]==bj) return; //已经染过需要的色了就不需要在遍历了
c[dian]=bj;//对这个点进行染色
used[dian]=1;//标记这个点用过了
x++;
for(int i=0;i<q[dian].size();i++) dfs(q[dian][i],bj^1);//^异味运算符,t^1如果t是1得出的就是 0如果是0得出的就是1也就是这边换个颜色进行染色
}
int main(){
int n,m;//n个点,m条边
cin>>n>>m;
for(int i=0;i<m;i++){
int v,u;
cin>>u>>v;//u为一个点,v为一个点,所以是一个无向图
q[u].push_back(v);
q[v].push_back(u);//无向图需要双向存边
}//建立好了图就该想一下怎么放河蟹 封锁所有的道路需要多少河蟹,相邻点的河蟹会打架
int ans=0;
for(int i=1;i<=n;i++){//遍历每一个点去放河蟹 案例太简单了,复杂起来本来写的就不适用了
if(used[i]==0){
x=0;
memset(c,-1,sizeof(c));//把c数组初始化为-1
dfs(i,0);
int t=0;
for(int i=1;i<=n;i++) if(c[i]==1) t+=c[i];
ans+=min(t,x-t);
}
}
cout<<ans;
return 0;
}
我还在题解里面学到的就是这个 if(c[i]==1) t+=c[i];可以写为 t+=c[i]==1
dfs和bfs基础还不过关呢