目录
1.危险系数
题目
抗日战争时期,冀中平原的地道战曾发挥重要作用。
题目描述
地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。
我们来定义一个危险系数 DF(x,y):
对于两个站点 x 和 y, 如果能找到一个站点 z,当 z 被敌人破坏后,x和 y 不连通,那么我们称 z 为关于 x,y 的关键点。相应的,对于任意一对站点 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
说明/提示
时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛
题解
思路:先创建无向图,运用广搜方法,先搜索从起点st是否能道道终点en,若不能直接输出-1,结束程序。若是能,则开始列举每一个点,查看是否是关键点,是则总数sum加1,最后输出结果sum。
如何确定是否是关键点:
运用广度优先搜索,在点是参数传入的点时,跳出循环进行下一次循环,如果这样还能达到终点,则说明他不是关键点。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m, u,v, i,b1,sum, b[2005];
queue<int> q;//广搜
vector<int> a[2005];//记录图
void bfs(int st,int en){
q.push(s);
b[s]=1;
//进行广度优先搜索
while(!q.empty()){
for(int j=0;j<a[q.front()].size();j++){
int x = a[q.front()][j];
if(x == e){
b1 = 1;//如果达到终点,那就改变b1
while(!q.empty()) q.pop();//要循环每个点,所以结束后要清空q
return ;
}
if(x == i || b[x] == 1) continue;//去除这个点,看是否为关键点
q.push(x);
b[x]=1;
}
q.pop();
}
return;
}
int main(){
cin>>n>>m;
for(int j = 0;j<m;j++){
cin>>u>>v;
//记录无向图 双向记录
a[u].push_back(v);
a[v].push_back(u);
}
cin>>u>>v;
bfs(u,v);//输入起点,终点
//判断是否可以达到,不可以直接输出-1
if(b1 == 0) cout<<“-1”;
//可以到达的话,遍历每个点,判断是否是关键点
else{
for(i=1;i<=n;i++){
if(i==u || i==v) continue;
//重新初始化
b1=0;
memset(b,0,sizeof(b));
bfs(u,v);
if(b1 == 0) sum++;
}
cout<<sum;
}
return 0;
}
2.图的遍历
题目
给出 N个点,M 条边的有向图,对于每个点 v,求 A(v)A(v) 表示从点 vv 出发,能到达的编号最大的点。
输入格式
第 1 行 2 个整数 N,M,表示点数和边数。
接下来 M 行,每行 2 个整数 U_i,V_i,表示边 (U_i,V_i)(Ui,Vi)。点用 1,2,3,…,N 编号。
输出格式
一行 N 个整数 A(1),A(2),...,A(N)。
输入输出样例
输入 #1
4 3 1 2 2 4 4 3
输出 #1
4 4 3 4
说明/提示
- 对于 60\%60% 的数据,1 \leq N,M \leq 10^31≤N,M≤103。
- 对于 100\%100% 的数据,1 \leq N,M \leq 10^51≤N,M≤105。
题解
图的基础,运用vector+数组来存储图:vector<int> a[]。再加上bfs遍历,最后得出答案。
这道题要求找到到达的最大点,运用反向思维,反向建边。并且从最大的点开始,往小的点走,这样搜索出来的第一个点就是最大的点,直接输出答案。
代码
#include<bits/stdc++.h>
using namespace std;
const int max1 = 1e5+5;
int n,m, v,u;
vector<int> a[max1];//记录图
int b[max1];//记录正确的点
void dfs(int x, int y){
if(b[x]) return ;//设置跳出dfs条件:访问过则跳出
b[x] = y;
for(int i = 0;i<a[x].size();i++) dfs(a[x][i],y);
}
int main(){
cin>>n>>m;
for(int i = 0;i<m;i++){
cin>>u>>v;
a[v].push_back(u);//反向建边
}
for(int i = n; i>0; i--) dfs(i,i);//从最大的开始,往小的走
for(int i = 1;i<=n;i++) cout<<b[i]<<" ";
return 0;
}
3.封锁仰光大学
题目
曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。
阳光大学的校园是一张由 n 个点构成的无向图,n个点之间由 m条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。
询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。
输入格式
第一行两个正整数,表示节点数和边数。 接下来 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
说明/提示
【数据规模】
对于 100\%100% 的数据,1\le n \le 10^41≤n≤104,1\le m \le 10^51≤m≤105,保证没有重边。
题解
搜索每一条边发现能过..
思路和第二题差不多,但是最后输出的答案要选择最小的,最后添加一个比较过程就好。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m, u,v, x,sum = 0, b[10010],c[10010];
vector<int> a[10010];
void dfs(int k,int t){
//冲突直接输出答案,并且结束程序
if(c[k] != -1&& c[k] != t){
cout<<"Impossible";
exit(0);
}
//设置跳出dfs条件
if(c[k] == t) return;
c[k]=t;
b[k]=1;
x++;
for(int i=0; i<a[k].size(); i++) dfs(a[k][i],t^1);
}
int main(){
cin>>n>>m;
for(int i=0; i<m; i++){
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
for(int i=1;i<=n;i++){
if(!b[i]){
x=0;
memset(c,-1,sizeof(c));//重新初始化
dfs(i,0);//一个一个搜
int y=0;
for(int i=1;i<=n;i++) y+=c[i]==1;
sum += min(y,x-y);//记录最小值
}
}
cout<<sum;
return 0;
}