标签:最短路 memset 清空 size 矛盾 possible false find 二分
算法流程(以点来扩展):
初始化dist [i] 为 正无穷
for i 0 ~ n
? 先集合外距离最近的点 赋值给 t
? 用 t 更新 其他点到 集合 的距离
? st[t] = true;
? * 其中 ,点 到 集合的距离,定义为 ,集合外一点,到集合内的点的距离,最小的那条边
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 510,INF = 0x3f3f3f3f;
int g[N][N],dist[N],n,m;
bool st[N];
int prim(){
int ret = 0;
memset(dist,0x3f,sizeof dist);
for(int i = 0;i < n; ++i){
int t = -1;
for(int j = 1;j <= n; ++j){ // 选取集合外一点,到集合内点距离最小的点
if(!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
}
st[t] = 1;
if(i && dist[t] == INF) return -1; // 如果 当前选的最小的点为INF,说明不连通,第一次除外
// 因为 第一次 集合中没有元素
if(i) ret += dist[t];// 除了第一次,之后的每一次,dist t 都代表一条边
// 先累加,在更新,(不然就会被 负的自环搞崩, 例如 1-1 ,权值为 -10)
for(int j = 1;j <= n; ++j) dist[j] = min(dist[j],g[t][j]); // 因为 t 已经被选到集合中去了
// 这个for的意思就是, 其他点能否通过 集合中的 t 点 缩短,j点到集合的距离
}
return ret;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int u,v,w;
cin >> n >> m;
for(int i = 0;i <= n; ++i)
for(int j = 0;j <= n; ++j)
g[i][j] = g[j][i] = INF;
while(m--){
cin >> u >> v >> w;
g[u][v] = g[v][u] = min(g[u][v],w);
}
int ans = prim();
cout << ans ;
return 0;
}
算法流程(以边来扩展,并查集的思想)
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 2e5 + 10,N = 1e5 + 10;
int p[N],n,m;
struct Edge{
int a,b,w;
bool operator < (const Edge & W) const{
return w < W.w;
}
}edges[M];
int find(int x){
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int cnt = 0,ret = 0;
cin >> n >> m;
for(int i = 0;i < m; ++i){
cin >> edges[i].a >> edges[i].b >> edges[i].w;
}
sort(edges,edges + m);
for(int i = 1;i <= n; ++i) p[i] = i;
for(int i = 0;i < m; ++i){
int a = edges[i].a,b = edges[i].b,w = edges[i].w;
a = find(a),b = find(b);
if(a != b){
p[a] = b;
ret += w;
cnt ++;
}
}
if(cnt < n-1) cout << "impossible";
else cout << ret ;
return 0;
}
性质:
一个图是二分图 当且仅当 图中不含 奇数环
环: 从一个点出发,又回到出发点的路径
奇数环 : 环当中边的数量 是 奇数
so, 如果一个图中有奇数环,那么它一定不是二分图
证明:环当中的第一个点属于左边,第二个点,一定属于右边,。。依次类推
? 假如环是奇数,我们可以推出,出发点属于 右边,与已知矛盾。。
算法流程:
for i 1 ~ n
如果 i 未染色
dfs(i) ,把 i 所在的连通块都染色一遍
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
int e[N],ne[N],w[N],h[N],idx,n,m;
int color[N];
void add(int a,int b,int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx ++;
}
bool dfs(int u,int c){
color[u] = c;
for(int i = h[u];i != -1;i = ne[i]){
int j = e[i];
if(!color[j]){
if(!dfs(j,3-c)) return 0;
}
else if(color[j] == c) return 0;
}
return 1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
memset(h,-1,sizeof h);
int a,b,c;
cin >> n >> m;
for(int i = 0;i < m; ++i){
cin >> a >> b >> c;
add(a,b,c);
add(b,a,c);
}
bool f = 1;
for(int i = 1;i <= n; ++i){
if(!color[i] && !dfs(i,1)){
f = 0;
break;
}
}
if(f) cout << "Yes";
else cout <<"No";
return 0;
}
算法流程:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510,M = 1e5 + 10;
int n1,n2,m;
int h[N],e[M],ne[M],idx,match[N];
bool st[N];
void add(int a,int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
bool find(int x){
for(int i = h[x];i != -1;i = ne[i]){
int j = e[i];
if(!st[j]){
st[j] = 1;
if(match[j] == 0 || find(match[j])){
match[j] = x;
return 1;
}
}
}
return 0;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int u,v,res = 0;
cin >> n1 >> n2 >> m;
memset(h,-1,sizeof h);
while(m--){
cin >> u >> v;
add(u,v);
}
for(int i = 1;i <= n1; ++i){
memset(st,0,sizeof st);
if(find(i)) res ++;
}
cout << res;
return 0;
}
标签:最短路 memset 清空 size 矛盾 possible false find 二分
原文地址:https://www.cnblogs.com/317zhang/p/11562264.html