五一  DAY 5


V  点  1----n

E  边

/*
Given a graph with N nodes and M unidirectional edges.
Each edge e_i starts from u_i to v_i and weights w_i
Output a travelsal from node 1 and output degree of each node. 给出了一个具有n个节点和m个单向边的图。
每边E_i从U_i开始到V_i,重量W_i
从节点1输出一个航迹,输出每个节点的度数。
*/
#include <bits/stdc++.h> using namespace std; const int N = ; int ideg[N], odeg[N], n, m, edg[N][N];
bool visited[N]; void travel(int u, int distance)
{
cout << u << " " << distance << endl; visited[u] = true;
for (int v = ; v <= n; v++)
if (edg[u][v] != - && !visited[v])
travel(v, distance + edg[u][v]); //if there is an edge (u, v) and v has not been visited, then travel(v)
}
int main()
{
cin >> n >> m;
memset(edg, -, sizeof edg); //没有边
memset(visited, false, sizeof visited); //没访问
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, edg[u][v] = w, odeg[u]++, ideg[v]++; //u出度,V入度
for (int i = ; i <= n; i++)
cout << ideg[i] << " " << odeg[i] << endl;
for (int i = ; i <= n; i++)
if (!visited[i]) travel(i, );
}

数组版本:

/*
Given a graph with N nodes and M unidirectional edges.
Each edge e_i starts from u_i to v_i and weights w_i
Output a travelsal from node 1 and output degree of each node. 给出了一个具有n个节点和m个单向边的图。
每边E_i从U_i开始到V_i,重量W_i
从节点1输出一个航图,输出每个节点的度数。
*/
#include <bits/stdc++.h> using namespace std; const int N = ; struct edge {
int u, v, w; edge *next;
edge(int _u, int _v, int _w, edge *_next):
u(_u), v(_v), w(_w), next(_next) {}
};
edge *head[N]; //List[u] stores all edges start from u 最前面节点
int ideg[N], odeg[N], n, m;
bool visited[N]; void add(int u, int v, int w)
{
edge *e = new edge(u, v, w, head[u]);
head[u] = e;
}
void travel(int u, int distance)
{
cout << u << " " << distance << endl; visited[u] = true;
for (edge *e = head[u]; e ; e = e -> next)
if (!visited[e -> v])
travel(e -> v, distance + e -> w); //if there is an edge (u, v) and v has not been visited, then travel(v)
}
int main()
{
cin >> n >> m;
memset(visited, false, sizeof visited);
memset(head, , sizeof head);
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, add(u, v, w), odeg[u]++, ideg[v]++;
for (int i = ; i <= n; i++)
cout << ideg[i] << " " << odeg[i] << endl;
for (int i = ; i <= n; i++)
if (!visited[i]) travel(i, );
}

指针版本:

Head   :   边的编号

#include <bits/stdc++.h>

using namespace std;

const int N = ;

struct edge {
int u, v, w, next;
}edg[N]; int head[N]; //List[u] stores all edges start from u
int ideg[N], odeg[N], n, m, cnt; //cnt: numbers of edges
bool visited[N]; void add(int u, int v, int w)
{
int e = ++cnt;
edg[e] = (edge){u, v, w, head[u]};
head[u] = e;
}
void travel(int u, int distance)
{
cout << u << " " << distance << endl; visited[u] = true;
for (int e = head[u]; e ; e = edg[e].next)
if (!visited[edg[e].v])
travel(edg[e].v, distance + edg[e].w); //if there is an edge (u, v) and v has not been visited, then travel(v)
}
int main()
{
cin >> n >> m; cnt = ;
memset(visited, false, sizeof visited);
memset(head, , sizeof head);
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, add(u, v, w), odeg[u]++, ideg[v]++;
for (int i = ; i <= n; i++)
cout << ideg[i] << " " << odeg[i] << endl;
for (int i = ; i <= n; i++)
if (!visited[i]) travel(i, );
} /*
Given a graph with N nodes and M unidirectional edges.
Each edge e_i starts from u_i to v_i and weights w_i
Output a travelsal from node 1 and output degree of each node.
*/

和传统二维数组相比,可以防止浪费,用多少开多少

#include <bits/stdc++.h>

using namespace std;

const int N = ;

struct edge {
int u, v, w;
};
//vector<edge> edg; //edg是变长数组
vector<edge> edg[N]; //n个变长数组
int ideg[N], odeg[N], n, m, cnt; //cnt: numbers of edges
bool visited[N]; void add(int u, int v, int w)
{
edg[u].push_back((edge){u, v, w});//(edge){u, v, w}强制类型转化
}
void travel(int u, int distance)
{
cout << u << " " << distance << endl; visited[u] = true;
for (int e = ; e < edg[u].size(); e++)
if (!visited[edg[u][e].v]) //以u出发的第e条出边
travel(edg[u][e].v, distance + edg[u][e].w); //if there is an edge (u, v) and v has not been visited, then travel(v)
}
int main()
{
cin >> n >> m; cnt = ;
memset(visited, false, sizeof visited);
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, add(u, v, w), odeg[u]++, ideg[v]++;
for (int i = ; i <= n; i++)
cout << ideg[i] << " " << odeg[i] << endl;
for (int i = ; i <= n; i++)
if (!visited[i]) travel(i, );
} /*
Given a graph with N nodes and M unidirectional edges.
Each edge e_i starts from u_i to v_i and weights w_i
Output a travelsal from node 1 and output degree of each node.
*/

     MST问题

也就是保留点,删除边(不一定每个点都要留下)

生成树不唯一,数量是指数级别

蓝色的边和点构成一个生成树

红色的边和点构成一个生成树

瓶颈生成树

显然红色的树更合题意

所以此处可以用到并查集

最常用

把边拿掉,一点一点加进去

判断是否连通,并查集

为什么克鲁斯卡尔是对的

反正最后还是要吧a,v,连起来,早连接,权值小

严谨证明:

消圈算法(麻烦,不用)

假设原图有个圈

不断断开权值最大边

剩下的就是最小生成树

#include <bits/stdc++.h>

using namespace std;

const int maxn = ;
struct edge {
int u, v, w;
}edg[maxn];
int n, m, p[maxn], ans = ; bool cmp(edge a, edge b) //小到大
{return a.w < b.w;}
int findp(int t)
{return p[t] ? p[t] = findp(p[t]) : t;}
bool merge(int u, int v)
{
u = findp(u); v = findp(v);
if (u == v) return false;
p[u] = v; return true;
}
int main()
{
cin >> n >> m;
for (int i = , u, v, w; i <= m; i++)
cin >> u >> v >> w, edg[i] = (edge){u, v, w};
sort(edg + , edg + m + , cmp); for (int i = ; i <= m; i++)
if (merge(edg[i].u, edg[i].v)) //并茶几
ans = max(ans, edg[i]. w);
cout << ans << endl;
}

Prim 

有些麻烦

先选择一号点,所有出边中最小的,联通,

然后找距离连通块最近的点,联通

总结: 先选择一号点,找出与当前联通快最小的边

(一个联通快,不断扩大)

Kosaraju

N个连通块,不断合并

第一轮每个连通块找到与他相连的最小边

(用堆优化)

给出一张图

简单路径:不经过重复的点

鬼畜路径:可以转圈圈

路径的长度:

路径中所有边,边权值和

  SSP

用中心点更新最短路

#include <bits/stdc++.h>

using namespace std;

const int N = ;
const int inf = << ; int d[N][N], n, m; //邻接矩阵存图
int main()
{
cin >> n >> m;
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
{
if(i==j) d[i][j]=; //d[i][i]应该为0 ,我到我自己
else d[i][j]=inf;
} //初始化无穷大 for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, d[u][v] = min(d[u][v], w); //处理重边 for (int k = ; k <= n; k++)
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
//必须先枚举中间点 //可以求出任意两点间的最短路径
}

一般来说题目只能做n<=500

结束后枚举d[u][u]如果有负数,证明有负权环

Floyd不可以处理负权环,但是可以判定有无

[代码]:

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;
const int inf = << ; struct edge{
int u, v, w;
}edg[N];
int d[N], n, m, S;
int main()
{
cin >> n >> m >> S;
for (int i = ; i <= n; i++) d[i] = inf;
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, edg[i] = (edge){u, v, w}; d[S] = ;
for (int i = ; i <= n; i++) //n点
for (int j = ; j <= m; j++) //枚举m条边
{
int u = edg[j].u, v = edg[j].v, w = edg[j].w;
d[v] = min(d[v], d[u] + w);
}
}

其实是bellman-ford的队列优化版

对比bellman-ford

一共n个点,全局松弛,把所有边都松弛一遍

假设点1可以更新点3,点5,

第一次全局更新的时候没有把2,4 更新的更小,下一轮也不用更新他了,否则就是重复计算

由于3,5被更新的更小,所以他们的出边继续更新才有机会把下面的点最短路径更新的更小

但是Spfa 会被网格图卡的很慢

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;
const int inf = << ; struct edge{ //邻接表
int u, v, w;
};
vector<edge> edg[N];
int d[N], n, m, S; //d是答案 queue<int> Queue;
bool inQueue[N];
int cntQueue[N]; void add(int u, int v, int w)
{
edg[u].push_back((edge){u, v, w});
}
int main()
{
cin >> n >> m >> S;
for (int i = ; i <= n; i++) d[i] = inf;
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, add(u, v, w); d[S] = ; inQueue[S] = true; Queue.push(S); //放进s点
while (!Queue.empty())
{
int u = Queue.front(); Queue.pop(); inQueue[u] = false;
for (int e = ; e < edg[u].size(); e++)
{
int v = edg[u][e].v, w = edg[u][e].w;
if (d[v] > d[u] + w)
{
d[v] = d[u] + w;
if (!inQueue[v])
{
Queue.push(v); ++cntQueue[v]; inQueue[v] = true;
if (cntQueue[v] >= n) {cout << "Negative Ring" << endl; return ;} //发现负权环
}
}
}
}
for (int i = ; i <= n; i++)
cout << d[i] << endl;
}

用起点松弛其余点,假设点 1 是距离S最近的点,找到这个点之后就用它再来更新下面的点

then,不管S和点1 ,找到d最小的点2 更新,它的 d是真实值

因为它已经被更新过了,而且外边的点的边权都比它大

[代码]:

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;
const int inf = << ; struct edge{
int u, v, w;
};
vector<edge> edg[N];
int d[N], n, m, S; bool relaxed[N]; //表示一个元素是否在队列
/*struct Qnode {
int u, du;
bool operator<(const Qnode &v)
const {return v.du < du;}
};
priority_queue<Qnode> PQueue;
*/
void add(int u, int v, int w)
{
edg[u].push_back((edge){u, v, w});
}
int main()
{
cin >> n >> m >> S;
for (int i = ; i <= n; i++) d[i] = inf;
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, add(u, v, w); d[S] = ;
for (int i = ; i <= n; i++)
{
int u = ; while (relaxed[u]) ++u;
for (int j = ; j <= n; j++)
if (!relaxed[j] && d[j] < d[u]) u = j;
//find a node u not relaxed yet with smallest d(u)
//寻找第一个不在队列里的 d最小的u
relaxed[u] = true;
for (int e = ; e < edg[u].size(); e++)
{
int v = edg[u][e].v, w = edg[u][e].w;
d[v] = min(d[v], d[u] + w);
}
}
for (int i = ; i <= n; i++)
cout << d[i] << endl;
}

[堆优化Dijkstra]:

//加优化
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + ;
const int inf = << ; struct edge{
int u, v, w;
};
vector<edge> edg[N];
int d[N], n, m, S; bool relaxed[N];
struct Qnode { //堆里元素
int u, du;
bool operator<(const Qnode &v) //const不能少
const {return v.du < du;} //小的在队顶
};
priority_queue<Qnode> PQueue; //优先队列 void add(int u, int v, int w)
{
edg[u].push_back((edge){u, v, w});
}
int main()
{
cin >> n >> m >> S;
for (int i = ; i <= n; i++) d[i] = inf;
for (int u, v, w, i = ; i <= m; i++)
cin >> u >> v >> w, add(u, v, w); d[S] = ; PQueue.push((Qnode){S, }); //需要更新的点
while (!PQueue.empty())
{
int u = PQueue.top().u; PQueue.pop(); //对不为空
if (relaxed[u]) continue; //松弛过就不松
//if edges staring from u are already relaxed, no need to relax again.
relaxed[u] = true; //打标机
for (int e = ; e < edg[u].size(); e++) //枚举出边
{
int v = edg[u][e].v, w = edg[u][e].w; //u v 是w的出边
if (d[v] > d[u] + w)
{
d[v] = d[u] + w;
PQueue.push((Qnode){v, d[v]});
//if d(v) is updated, push v into PQueue
}
}
}
for (int i = ; i <= n; i++)
cout << d[i] << endl;
}

有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图

找拓扑序的方法:

1.找出度为0 的点,放在拓扑序列最后面,指向该点的边删掉,与所删除的边起点出度数-1

2.重复以上操作,得出拓扑序

结论1 有拓扑序一定是DAG

结论2   任意DAG一定有拓扑序

任意DAG一定有出度为0的点,否则有环,

出度为0的点放在拓扑序最后

把这个点和他的入度边删去,图还是个DAG

同上操作,做完后就是拓扑序

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;
const int inf = << ; struct edge{
int u, v;
};
vector<edge> edg[N];
int n, m, outdeg[N], ans[N]; queue<int> Queue; //出度为0
void add(int u, int v)
{
edg[u].push_back((edge){u, v});
}
int main()
{
cin >> n >> m;
for (int u, v, i = ; i <= m; i++)
cin >> u >> v, add(v, u), outdeg[u]++; //找入度,倒着记录 for (int i = ; i <= n; i++)
if (outdeg[i] == ) Queue.push(i);
for (int i = ; i <= n; i++)
{
if (Queue.empty())
{printf("Not DAG"); return ;}
int u = Queue.front(); Queue.pop(); ans[n - i + ] = u; //倒着
for (int e = ; e < edg[u].size(); e++) //指向u的边删掉
{
int v = edg[u][e].v; //指向u的点 出度减少
if (--outdeg[v] == ) //先自减,再使用
Queue.push(v);
}
}
}

pro1   

考虑DAG上找单元最短路

1到不了3

1松弛出边7 5 出边肯定在自己后边

然后出边在更新自己出边,直达完成

自己被更新完就不能被改变了,他要继续更新自己出边

pro 2

考虑DAG求拓扑排序数量

(做不到)

LCA(写在这里啦)

ans=len(x)-len(t)+len(y)+len(t)

=len(x)+len(y)-2*len(t)

五一 DAY 5的更多相关文章

  1. 带你找到五一最省的旅游路线【dijkstra算法推导详解】

    前言 五一快到了,小张准备去旅游了! 查了查到各地的机票 因为今年被扣工资扣得很惨,小张手头不是很宽裕,必须精打细算.他想弄清去各个城市的最低开销. [嗯,不用考虑回来的开销.小张准备找警察叔叔说自己 ...

  2. 五一出门必备的手机APP神器 让你瞬间大开眼界

    如今我们手机上有各种各样的软件,但是比较实用的又有哪些呢?所以每次大家都会花上很久的时间去查找满意的软件吧!今天就给大家送上一波福利,因为五一小长假就要到来了,说不定大家会使用到呢! 轻颜相机 轻颜相 ...

  3. 五一,期待一场这样的旅行,提前预祝Csdner五一快乐

    五一,期待一场这样的旅行,提前预祝Csdner五一快乐 五一,你是否期待一次这样的旅行: 住在一间安静优美的小屋,在鸟鸣中起床,推窗有花香铺面而来.早餐过后,在阳光温暖的抚摸里,骑车踏青或光脚奔跑. ...

  4. GDOI2017 五一游玩记

    GDOI2017 到辣! 在五一比赛,成功躲了两天文化课. Day 0 早上睡到挺晚,想着同学在上课,我在睡觉,暗爽... 动车上,拿起电脑就是颓废,打模板!(然而真相是打了两个模板就开始颓了) 一天 ...

  5. 五一巨献,问答有礼,105QB送给IT互联网界的劳动人民

    活动主题:五一巨献,问答有礼,105QB送给IT互联网界的劳动人民活动时间:4月30日晚上10点~5月2日晚上10点活动期数:第1期,20150401 奖品:105QB获奖人数:20人1~5:每人10 ...

  6. Python 爬取 13 个旅游城市,告诉你五一大家最爱去哪玩?

    五一假期已经结束,小伙伴是不是都还没有玩过瘾?但是没办法,还有很多bug等着我们去写,同样还有需要money需要我们去赚.为了生活总的拼搏. 今年五一放了四天假,很多人不再只是选择周边游,因为时间充裕 ...

  7. 五一DAY1数论学习笔记

    by ruanxingzhi 整除性 如果a能把b除尽,也就是没有余数,则我们称a整除b,亦称b被a整除.(不是除以,是整除!!) 记作:\(a|b\) |这个竖杠就是整除符号 整除的性质 自反性 对 ...

  8. 五一 DAY 4

    DAY 4    2019.5.1 PART 1    进制转化 10 = 23+21= 1010(2)       = 32+30= 101(3) 进制转化常见问题: 1.十进制数 x ----&g ...

  9. 五一 DAY 7

    五一  DAY 7 P1514 引水入城 P1311 选择客栈 题解: P1315 观光公交 题解: 设 wait i 为最晚到达的旅客 arrive i 为到达i 的时刻 arrive i =max ...

随机推荐

  1. ulimit用法

    ulimit -a:显示当前所有的资源限制 -c:core文件大小 -f:设置创建文件的最大值 -n:设置内核可以同时打开的文件描述符的最大值 -p:设置管道缓冲区的最大值 -s:设置堆栈的最大值 - ...

  2. spring data 入门

    提出问题 我是Sping Data,是程序员的春天,因为我提供很多接口给开发人员, 减少程序员重复的写CRUD和分页等方法,你们也可以叫我春D,或者春帝,因为我很酷 解决问题 在Spring Data ...

  3. JS 详解 Cookie、 LocalStorage 与 SessionStorage-转载

    记录一下这些知识,有时候用到会忘记,对原文作者表达感谢. 附上原文链接:JS 详解 Cookie. LocalStorage 与 SessionStorage 基本概念 Cookie Cookie 是 ...

  4. keil 选项卡设置

    *1.optimization  : level2. *2. 2)硬件目标设置选项卡(Target),见图6所示. 图6 1:选择硬件目标设置选项卡 2:指定用于的晶振频率 3:在应用中可以选择实时操 ...

  5. Error creating bean with name 'objectMapperConfigurer' defined in class path resource

  6. idou老师教你学Istio 29:Envoy启动流程

    1. 功能概述 Envoy启动时,会启动一个进程,并在这个进程中启动很多线程,这样,可以启动很多worker线程,一般worker线程数与核心数相同,每个worker线程处理所有已配置的listene ...

  7. mysql运维相关

    1.为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?2.现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统 ...

  8. 1121 Django基本

    目录 Django前戏 一.课程导读 1.web应用 2.c/s b/s 架构 3.Python Web框架 二.原生socket服务 三.http协议 什么是http协议 四大特性 http工作原理 ...

  9. vue 后台获取文件流导出excel文件

    let params = { compStartTm: Date.parse(this.searchForm.compStartTm) / 1000, compEndTm: Date.parse(th ...

  10. react-router和react-router-dom的区别

    RR4 本次采用单代码仓库模型架构(monorepo),这意味者这个仓库里面有若干相互独立的包,分别是: react-router React Router 核心 react-router-dom 用 ...