1.Dijkstra
邻接矩阵:
#include<bits/stdc++.h>
using namespace std;
const int MaxV = 1000;
const int INF = 10000000;
int G[MaxV][MaxV];
int dis[MaxV];
int charge[MaxV];
bool vis[MaxV] = {false};
void Dijkstra(int s, int t,int n){
fill(dis,dis+MaxV,INF);
dis[0];
for(int i =0;i<n;i++){
int u =-1,Min =INF;
for(int j = 0;j<n;j++){
if(vis[j] == false && dis[j]<Min){
u = j;
Min = d[j];
}
}
if( u == -1) return;
vis[u] = true;
for(int v =0;v<n;v++;){
if(vis[v] == false&&G[u][v]!=INF&&d[u]+G[u][v]<d[v]){
d[v] = d[u] + G[u][v];
}
}
}
}
邻接表:
#include<bits/stdc++.h>
using namespace std;
const int MaxV = 1000;
const int INF = 10000000;
struct Node{
int v,dis,price;
};
vector<Node> Adj[MaxV];
int dis[MaxV];
int charge[MaxV];
bool vis[MaxV] = {false};
void Dijkstra(int s, int t,int n){
fill(dis,dis+n,INF);
fill(charge,charge+n,0);
dis[s] = 0;
for(int i = 0;i<n;i++){
int u = -1,min_dis = INF,min_free = INF;
for(int j =0;j<n;j++){
if(vis[j] == false && dis[j]<min_dis ){
u = j;
min_dis = dis[j];
}
}
if(u == -1 ) return;
vis[u] = true;
if(u == t){
return; // find out and end
}
//update the distance
for(int j = 0;j<Adj[u].size();j++){
int v = Adj[u][j].v;
int tmp_dis = dis[u] + Adj[u][j].dis;
int tmp_free = charge[u] + Adj[u][j].price;
if(vis[v] == false && tmp_dis < dis[v]){
dis[v] = tmp_dis;
charge[v] = tmp_free;
}else if(tmp_dis == dis[v] && tmp_free < charge[v]){ // 第二标尺;
charge[v] = tmp_free;
}
}
}
}
int main(){
int n,m,s,t;
int node1,node2,dd,pr;
while(scanf("%d%d",&n,&m)!=EOF && n!=0&&m!=0){
for(int i = 0;i<n;i++)
Adj[i].clear();
while(m--){
scanf("%d%d%d%d",&node1,&node2,&dd,&pr);
node1--;
node2--;// to be zero and begin
Node tmp;
tmp.v = node2;
tmp.dis = dd;
tmp.price = pr;
Adj[node1].push_back(tmp);
tmp.v = node1;
Adj[node2].push_back(tmp);
}
scanf("%d%d",&s,&t);
Dijkstra(s-1,t-1,n);
printf("%d %d\n",dis[t-1],charge[t-1]);
}
}
最短路径变形:
///第一点,需要知道路径是怎样走的
//加上前驱数组pre[MaxV];
for(int v =0;v<n;v++;){
if(vis[v] == false&&G[u][v]!=INF&&d[u]+G[u][v]<d[v]){
d[v] = d[u] + G[u][v];
pre[v] = u; // 前驱为u;
}
}
///第二点,第二尺度
//1.给边加上第二个边权(如花费最小)
//例子:邻接表的情况
for(int j = 0; j<Adj[u].size(); j++)
{
int v = Adj[u][j].v;
int tmp_dis = dis[u] + Adj[u][j].dis;
int tmp_free = charge[u] + Adj[u][j].price;
if(vis[v] == false && tmp_dis < dis[v])
{
dis[v] = tmp_dis;
charge[v] = tmp_free;
}
else if(tmp_dis == dis[v] && tmp_free < charge[v]) // 距离相同时花费最小
{
charge[v] = tmp_free;
}
}
//2.每个点上增加一个点权(如每个城市能收集到的物资),然后再最短路径有多条的时候要求
//点权和最大
//例子:邻接表的情况
for(int j = 0; j<Adj[u].size(); j++)
{
int v = Adj[u][j].v;
int tmp_dis = dis[u] + Adj[u][j].dis;
int tmp_weight = wei[u] + Adj[u][j].weight;
if(vis[v] == false && tmp_dis < dis[v])
{
dis[v] = tmp_dis;
wei[v] = tmp_weight ;
}
else if(tmp_dis == dis[v] && tmp_weight > wei[v]) // 距离相同时权重最大
{
wei[v] = tmp_free;
}
}
//3.直接问最短路径的个数
//增加一个数组就好了 num[]
//初始化是 num[s] = 1; 其余num[u] = 0;
for(int j = 0; j<Adj[u].size(); j++)
{
int v = Adj[u][j].v;
int tmp_dis = dis[u] + Adj[u][j].dis;
if(vis[v] == false && tmp_dis < dis[v])
{
dis[v] = tmp_dis;
num[v] = num[u];
}
else if(tmp_dis == dis[v] ) // 距离相同时权重最大
{
num[v]+ = num[u];
}
}
图论 :并集 连接图(最小生成树kruskal)
int pre[1010]; //存放第i个元素的父节点
int unionsearch(int x) //查找根结点
{
int root= x;
while(x!= pre[x]) //寻找根结点
x= pre[x];
while(root!= pre[root]) //路径压缩
{
int tmp = root;
root = pre[root];
pre[tmp ] = x;
}
return x;
}
void join(int root1, int root2) //判断是否连通,不连通就合并
{
int x, y;
x = unionsearch(root1);
y = unionsearch(root2);
if(x != y) //如果不连通,就把它们所在的连通分支合并
pre[x] = y;
}