为了能到远方,脚下的每一步都不能少.|

Zac-saodiseng

园龄:2年4个月粉丝:3关注:0

ACM预备队-week5(DFS/BFS/二分图)

[蓝桥杯 2013 国 C] 危险系数

题目链接:P8604 [蓝桥杯 2013 国 C] 危险系数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

割点:

删除这个顶点集合以所有顶点相关联的边以后,图的连通分量增多

其实就是求图的割点,找到“关键枢纽”,因为是稀疏图,所以用邻接表存图。

遍历起点->终点的所有路径(DFS),在遍历过程中,如果可以到达终点,则给中途经过的点的标记+1,找到从起点到终点路径数目相同的点(除去起点和终点),该数目即为ans

复制代码
 1 #include <bits/stdc++.h>
 2 #define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
 3 using namespace std;
 4 const int N=2010;
 5 int n,m;
 6 bool vis[N];
 7 int st,ed;
 8 int tot;//表示起点到终点的路径数 
 9 int cnt[N];
10 int ans;
11 int h[N],e[N],ne[N],idx; 
12 void add(int a,int b)
13 {
14     e[idx]=b,ne[idx]=h[a],h[a]=idx++;
15 }
16 void dfs(int u)
17 {
18     vis[u]=true;
19     if(u==ed)
20     {
21         tot++;
22         for(int i=1;i<=n;i++)
23         {
24             if(vis[i])cnt[i]++;
25         }
26         return;
27     }
28     for(int i=h[u];i!=-1;i=ne[i])
29     {
30         int j=e[i];
31         if(!vis[j])
32         {
33             dfs(j);
34             vis[j]=0;
35         }
36     }
37     return;
38     
39 }
40 int main()
41 {
42     io;
43     cin>>n>>m;
44     memset(h,-1,sizeof h);
45     for(int i=0;i<m;i++)
46     {
47         int a,b;
48         cin>>a>>b;
49         add(a,b),add(b,a);
50     }
51     cin>>st>>ed;
52     dfs(st);
53     for(int i=1;i<=n;i++)
54     {
55         if(cnt[i]==tot)ans++;
56     }
57     ans-=2;
58     cout<<ans;
59     return 0;
60 }
复制代码

图的遍历

题目链接:P3916 图的遍历 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

稀疏图邻接表存图,反向真妙我真傻,从大到小遍历,经过的直接赋值最大点,O(n)复杂度,要不然1e5(⊙﹏⊙),基本正向就挂了

反向建图+DFS,不会缩点qwq

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e5+10;
 4 int e[N],ne[N],idx,h[N];
 5 bool st[N];
 6 
 7 int ans[N];//用来存储答案
 8 void add(int a,int b)//表示在a后加入b这个点
 9 {
10     e[idx]=b,ne[idx]=h[a],h[a]=idx++;
11 }
12 void dfs(int u,int a)//对u这个节点赋值a
13 {
14     ans[u]=a;
15     st[u]=true;
16     for(int i=h[u];i!=-1;i=ne[i])
17     {
18         int j=e[i];
19         if(!st[j])dfs(j,a);
20     }
21 }
22 int main()
23 {
24     memset(h,-1,sizeof h);
25     int n,m;
26     cin>>n>>m;
27     for(int i=0;i<m;i++)
28     {
29         int a,b;
30         cin>>a>>b;
31         add(b,a);//反向建图
32     }
33     for(int i=n;i>=1;i--)
34     {
35         if(!st[i])dfs(i,i);
36     }
37     for(int i=1;i<=n;i++)
38     cout<<ans[i]<<' ';
39 }
复制代码

【福建省历届夏令营】阳光大学

题目链接:P1330 封锁阳光大学 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

二分图,其实就是想把相邻的两个点染成不同的颜色,在每个连通块中加上两个颜色数目最小的点的数量,最后即为我要堵的答案

复制代码
 1 #include <bits/stdc++.h>
 2 #define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) 
 3 using namespace std;
 4 const int N=1e5+10;
 5 int n,m;
 6 int h[N],e[N],ne[N],idx;
 7 void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;} 
 8 int cnt[3];//表示1和2的二分子连通图各自的数量 
 9 int color[N];
10 bool dfs(int u,int c)//节点是u,c表示颜色 
11 {
12     color[u]=c;
13     cnt[c]++;
14     for(int i=h[u];i!=-1;i=ne[i])
15     {
16         int j=e[i];
17         if(!color[j])//如果j这个点还没被染色 
18         {
19             if(!dfs(j,3-c))return false;//如果接下来染色失败 
20         }
21         else if(color[j]==c)return false;//如果染过色了,但是是冲突的 
22     }
23     return true;
24 }
25 signed main()
26 {
27     io;
28     cin>>n>>m;
29     memset(h,-1,sizeof h);
30     while(m--){int a,b;cin>>a>>b;add(a,b);add(b,a);}
31     int ans=0;
32     for(int i=1;i<=n;i++)
33     {
34         cnt[1]=0,cnt[2]=0;
35         if(!color[i])
36         {
37             if(!dfs(i,1)){cout<<"Impossible";return 0;}//没有被染色并且染色后还矛盾了
38         }
39         ans+=min(cnt[1],cnt[2]);
40     }
41     cout<<ans;
42     return 0;
43 }
复制代码

 

本文作者:Zac-saodiseng

本文链接:https://www.cnblogs.com/Zac-saodiseng/p/16927263.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Zac-saodiseng  阅读(35)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起