#搜索与图论
-
首先花费了好长时间才弄明白,邻接表的储存原理。这个笔记上有。
-
第二就树的重心这个题,也是花费将近一个小时才弄明白。
-
还有就是链表的范围至少是数据范围的俩倍,否则就会越界。产生错误答案,这题就遇到了。
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int h[N] , e[N] , ne[N] ,idx ,ans = N ,n; bool st[N];//用于记录状态 void add (int a , int b) { e[idx] = b , ne[idx] = h[a] , h[a] = idx ++; }//给 a,b 之间添加一条边。 int dfs (int u) { st[u] = true; int size_ = 0 , sum = 0; for (int i = h[u] ; i != -1 ; i = ne[i]) { int j = e[i]; if (st[j]) continue; int s = dfs(j); size_ = max (s , size_); sum += s; } size_ = max (n - sum - 1 , size_);n 是所有结点的个数,sum 是某一棵子树的大小,-1 是因为是以这个点作为了重心。 ans = min (ans , size_); //cout<<ans<<' '<<size_<<endl; return sum + 1;//返回sum + 1 是因为当sum = 0 时,此时至少还有一个结点。 } int main() { cin>>n; memset(h , -1 , sizeof h); for (int i = 0 ; i < n - 1 ; i ++) { int a ,b; cin>>a>>b; add(a ,b) , add(b , a); } //cout<<"------"<<endl; dfs(1); cout<<ans; return 0; }
- 图的宽度优先遍历
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10 ;
int e[N * 2] , ne[N * 2] , h[N] ,idx , n ,m , d[N];
queue<int>q;
void add (int a ,int b)
{
e[idx] = b , ne[idx] = h[a] , h[a] = idx ++;
}
void bfs ()
{
q.push(1);
d[1] = 0;
while (q.size())
{
int t = q.front();
q.pop();
for (int i = h[t] ; i != -1 ; i = ne[i])
{
int j = e[i];
if (d[j] == -1){
q.push(j);
d[j] = d[t] + 1;
}
if (j == n){
cout<<d[j]<<endl;
return ;
}
}
}
cout<<-1<<endl;
}
int main()
{
cin>>n>>m;
memset (d , -1 , sizeof d);
memset (h , - 1 , sizeof h);
for (int i = 0 ; i < m ; i ++)
{
int a , b;
cin>>a>>b;
add(a , b);
}
bfs();
return 0;
}
拓扑排序
首先说明几个图论里的几个概念,
入度:指向自己的边数
出度:指向别人的边数
一个拓扑图一定是一个有向无环图,有环的话,不能构成拓扑序列。
入度为零的点一定排在最前面的点,因为没有边指向它,所以说它就是起点。
拓扑排序的基本思想就是让所有入度为0的点都放在最前面,因为他们一定是起点,然后遍历每一个入度为0点指向的边,如果说,遍历到的这条边,我们就把这条边删去也就是指向的点的入度减1,当他入度为0时,那个他也就成为一个起点。
- 这里还必须说一下,用数组来模拟队列,确实有不一样的好处,那就是数据还保存着。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int h[N] , e[N * 2] , ne[N * 2] , idx , d[N] ,n ,m;//d[N] 表示度数
int q[N];
void add (int a , int b)
{
e[idx] = b , ne[idx] = h[a] , h[a] = idx ++;
}
bool tuoposort ()
{
int hh = 0 , tt = -1;
for (int i = 1 ; i <= n ; i ++){
if (d[i] == 0) {
q[ ++tt] = i;
}
}
//cout<<tt<<"-"<<endl;
while (hh <= tt)
{
int t = q[hh ++];
for (int i = h[t] ; i != -1 ; i = ne[i]){
int j = e[i];
d[j] --;
if (d[j] == 0) q[ ++tt] = j;
}
}
//cout<<tt<<endl;
return tt == n - 1;
}
int main()
{
cin>>n>>m;
memset (h , -1 ,sizeof h);
for (int i = 0 ; i < m ; i ++)
{
int a , b;
cin>>a>>b;
add(a ,b);
d[b] ++;
}
//cout<<"------"<<endl;
if (tuoposort())
{
for (int i = 0 ; i < n ; i ++) cout<<q[i]<<' ';
}
else puts("-1");
return 0;
}
朴素版的迪杰斯特拉算法
具体思路纸质笔记上有。
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int g[N][N] , n ,m ,dist[N];
bool st[N];
int dijkstra (int n)
{
//cout<<n<<endl;
memset (dist , 0x3f3f3f , sizeof dist);
dist[1] = 0 ;
for (int i = 0 ; i < n ; i ++)
{
int t = -1 ;
for (int j = 1 ; j <= n ; j ++){
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
}
//cout<<t<<' '<<dist[t]<<endl;
st[t] = true;
for (int j = 1 ; j <= n ; j ++)
dist[j] = min (dist[j] , dist[t] + g[t][j]);
}
if (dist[n] == 0x3f3f3f3f) return -1;
else return dist[n];
}
int main()
{
int n , m;
cin>>n>>m;
memset (g , 0x3f3f3f , sizeof g);
while (m --)
{
int x , y , z;
cin>>x>>y>>z;
g[x][y] = min (g[x][y] , z);
}
cout<<dijkstra(n)<<endl;
return 0;
}
堆优化版的迪杰斯特拉算法
#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
int h[N] , e[N] , ne[N] ,w[N] ,idx ,dist[N];
bool st[N];
typedef pair<int,int>PII;
void add (int a , int b , int c)
{
e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++;
}
int dijkstra (int n)
{
//cout<<n<<"-----------"<<endl;
memset (dist , 0x3f3f3f3f , sizeof dist);
priority_queue<PII , vector<PII> ,greater<PII> > heap;
dist[1] = 0;
heap.push({0,1});
while (heap.size())
{
auto t = heap.top();
heap.pop();
int distance = t.first , ver = t.second;
//cout<<ver<<' '<<distance<<endl;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver] ; i != -1 ; i = ne[i])
{
int j = e[i];
if (distance + w[i] < dist[j]){
dist[j] = distance + w[i];
heap.push({dist[j] ,j });
}
}
}
if (dist[n] == 0x3f3f3f3f) return -1;
else return dist[n];
}
int main()
{
int n , m;
cin>>n>>m;
memset(h , -1 , sizeof h);
while (m --)
{
int x , y , z;
cin>>x>>y>>z;
add(x , y ,z);
}
cout<<dijkstra(n)<<endl;
return 0;
}
floyd算法求多源最短路
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int g[N][N] ;
int n ,m ,k;
void floyd ()
{
for (int k = 1 ; k <= n ; k ++)
{
for (int i = 1 ; i <= n ; i ++)
{
for (int j = 1 ; j <= n ; j ++)
{
g[i][j] = min (g[i][j] , g[i][k] + g[k][j]);
}
}
}
}
int main()
{
cin>>n>>m>>k;
for (int i = 1 ; i <= n ; i ++)
{
for (int j = 1 ; j <= n ; j ++)
{
if (i == j) g[i][j] = 0;
else g[i][j] = 1e9;
}
}
while (m --)
{
int x , y ,z ;
cin>>x>>y>>z;
g[x][y] = min(g[x][y] , z);
}
floyd();
while (k --)
{
int x , y;
cin>>x>>y;
if (g[x][y] > 1e9 / 2) cout<<"impossible"<<endl;
else cout<<g[x][y]<<endl;
}
return 0;
}
bellman_ford算法
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
struct Edge
{
int a ,b ,w;
}edges[100010];
int backup[N] , dist[N];
int n ,m ,k;
int bellman_ford ()
{
memset (dist , 0x3f , sizeof dist);
dist[1] = 0;
for (int i = 0 ; i < k ; i ++)
{
memcpy (backup , dist , sizeof dist);
for (int j = 0 ; j < m ; j ++)
{
int a = edges[j].a , b = edges[j].b , c = edges[j].w;
dist[b] = min (dist[b] , backup[a] + c);
}
}
if (dist[n] > 0x3f3f3f3f / 2) return -1;
else return dist[n];
}
int main()
{
cin>>n>>m>>k;
for (int i = 0 ; i < m ; i ++)
{
cin>>edges[i].a>>edges[i].b>>edges[i].w;
}
if (bellman_ford() == -1) cout<<"impossible";
else cout<<dist[n];
return 0;
}
spfa求最短路
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int idx , n , m;
int h[N] , e[N] ,w[N] , ne[N] ,dist[N];
void add (int a , int b , int c)
{
e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++;
}
queue<int>q;
bool st[N];
int spfa ()
{
memset (dist , 0x3f3f3f3f ,sizeof dist);
dist[1] = 0;
q.push(1);
st[1] = true;
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t] ; i != -1 ; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (!st[j]){
st[j] = true;
q.push(j);
}
}
}
}
if (dist[n] > 0x3f3f3f3f / 2) return -1;
else return dist[n] ;
}
int main()
{
cin>>n>>m;
memset (h , -1 , sizeof h);
while (m --)
{
int x ,y ,z;
cin>>x>>y>>z;
add(x , y ,z);
}
if (spfa() == -1) cout<<"impossible";
else cout<<dist[n];
return 0;
}
spfa判负环
#include<bits/stdc++.h>
using namespace std;
const int N = 2010 , M = 10010;
int h[N] ,ne[M] ,e[M] ,w[M] ,dist[N] , cnt[N];
int idx , n , m;
void add (int a , int b , int c)
{
e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++;
}
queue<int>q;
bool st[N];
bool spfa ()
{
memset (dist , 0x3f , sizeof dist);
dist[1] = 0;
for (int i = 1 ; i <= n ; i ++)
{
st[i] = true;
q.push(i);
}
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t] ; i != -1 ; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
cnt[j] = cnt[t] + 1;
if (cnt[j] > n) return true;
if (!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
return false;
}
int main()
{
cin>>n>>m;
memset (h , -1 , sizeof h);
while (m --)
{
int x , y , z;
cin>>x>>y>>z;
add(x , y , z);
}
if (spfa()) puts("Yes");
else puts("No");
return 0;
}