prim算法
算法思路
第一个点收入set
然后更新n次,每次将距离最近的点纳入集合,如果距离都是INF,那么不存在最小树
求最小生成树 适用于稠密图
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 1e5+10,M = 505,INF = 0x3f3f3f3f;
int n,m;
int dist[N];
int v[M][M];
int vis[M];
int prim(){
memset(dist ,INF,sizeof dist);
int res = 0;
for(int i = 0;i<n;i++){
int t = -1;
for(int j = 1;j<=n;j++){
if(!vis[j]&&(t==-1||dist[t]>dist[j]))
t=j;
}
if(i && dist[t]==INF) return INF;
if(i)
res += dist[t];
for(int j = 1;j<=n;j++)
dist[j] = min(dist[j],v[t][j]);
vis[t] = true;
}
return res;
}
int main() {
cin>>n>>m;
memset(v,INF,sizeof v);
for(int i = 0;i<m;i++){
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
v[b][a] = v[a][b] = min(v[a][b],w);
}
int ans = prim();
if(ans == INF) cout<<"impossible";
else cout<<ans;
return 0;
}
kruskal算法
思路
从小到大排序
并查集查是否在同一个集合中
全部弄完就行
并查集合并操作
a = find(a)
b = find(b);
p[a] = b;
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int n,m;
int p[N];
struct edge{
int a,b,w;
}e[N];
int find(int k){
if(k!=p[k]) p[k] = find(p[k]);
return p[k];
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
int res = 0,cnt = 1;
void kruskal(){
sort(e+1,e+m+1,cmp);
for(int i = 1;i<=m;i++){
int a = e[i].a,b = e[i].b,w = e[i].w;
if(cnt == n)
return ;
a = find(a);
b = find(b);
if(a!=b){
cnt++;
res +=w;
p[a] = b;
// cout<<a<<' '<<b<<' '<<w<<endl;
}
}
}
int main() {
cin>>n>>m;
for(int i = 1;i<=m;i++){
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
e[i] = {a,b,w};
}
for(int i = 1;i<=n;i++) p[i] = i;
kruskal();
if(cnt == n)
cout<<res;
else
cout<<"impossible";
return 0;
}
二分环
一个图是二分图当且仅当 图中不含奇数环(环中的个数不为奇数
染色法
注意vector
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e5+10;
int n,m;
int se[N];
vector<int> v[N];
bool error_flag = 1;
bool dfs(int i,int s){
se[i] = s;
int new_s = 3-s;
for(int j = 0;j<v[i].size();j++){
if(se[v[i][j]]==0){
if(!dfs(v[i][j],new_s)) return false;
}
else if(se[v[i][j]]==s)
{
return false;
}
}
return true;
}
int main() {
cin>>n>>m;
while(m--){
int a,b;
scanf("%d%d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
for(int i = 1;i<=n;i++){
if(se[i]==0)
if(!dfs(i,1)) {
error_flag = false;
break;
}
}
if(error_flag) cout<<"Yes";
else cout<<"No";
return 0;
}
匈牙利算法(常用) O(nm)
用于求二分图的最大匹配
左边的点匹配的时候,找到右边的点已经匹配过了的点去找别的点,如果可以那就成,不可以就看下一个点。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int N = 1e5+10,M = 505;
vector<int> v[M];
int n1,n2,m;
bool st[M];
int match[M];
bool find(int x){
for(int i = 0;i<v[x].size();i++){
int j = v[x][i];
if(!st[j]){
st[j] = true;
if(match[j]==0|| find(match[j])){
match[j] = x;
return true;
}
}
}
return false;
}
int main() {
cin>>n1>>n2>>m;
while (m--){
int a,b;
scanf("%d%d",&a,&b);
v[a].push_back(b);
}
int res = 0;
for(int i = 1;i<=n1;i++){
memset(st, false, sizeof st);
if(find((i))) res++;
}
cout<<res;
return 0;
}