五一  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. mysql使用GTID跳过事务

    GTID跳过有两种方法,一种是普通的跳过一个事务的方法,另外一个是在基于主库搭建新的slave的时候.一.普通跳过一个事务的方法.通过show slave status\G找到冲突的GTID号.然后执 ...

  2. 虚拟机配置双网卡适配器后(桥接和NAT模式),重新打开后两个适配器的ip都没有了(重启网卡报Job for network.service failed because the control process exited with error code)

    科普双网卡适配器的好处: 我是配了一个桥接模式的网卡和一个NAT模式的网卡,桥接模式,也就是将虚拟机的虚拟网络适配器与主机的物理网络适配器进行交接,虚拟机中的虚拟网络适配器可通过主机中的物理网络适配器 ...

  3. Ubuntu系统---C++之Eclipse IDE 编译器安装

    Ubuntu系统---C++之Eclipse IDE 编译器安装 Eclipse是一个基于Java的.开放源码的.可扩展的应用开发平台,它为编程人员提供了一流的Java集成开发环境(Integrate ...

  4. Codeforces 348 D - Turtles

    D - Turtles 思路: LGV 定理 (Lindström–Gessel–Viennot lemma) 从{\(a_1\),\(a_2\),...,\(a_n\)} 到 {\(b_1\),\( ...

  5. MongoDB C#samus驱动

    MongoDB的c#驱动有两种,官方驱动和samus驱动,不过我更喜欢samus驱动,因为samus驱动提供了丰富的linq操作. 官方驱动:https://github.com/mongodb/mo ...

  6. 0003SpringBoot整合SpringDataJPA

    SpringBoot整合SpringDataJpa步骤如下: 1.添加data-jpa起步依赖(pom.xml) 2.添加数据库驱动坐标.添加Junit起步依赖(pom.xml) 3.添加数据库连接信 ...

  7. c语言1博客作业11

    一.本周作业头 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 http://edu.cnblogs.com/campus/zswxy/SE2019-4/homework/10125 我 ...

  8. airflow--Error: Already running on PID 22603 (or pid file '/home/rdev/airflow/airflow-webserver.pid' is stale)

    kill这个残留进程然后直接重新启动airflow webserver就OK (wqbin) rdev@testhk1:~/etl/py_etl/warehouse$ cat /home/rdev/a ...

  9. win10笔记本连接wifi出现:您的计算机配置似乎是正确的,但该配置或资源(DNS服务器)检测到有响应

    问题上图: 一直以来连接网线使用,很少使用WiFi了,在网线不好使的时候使用wifi发现并不怎么好用,甚至上不了网页,但是那时候也不怎么在意,不过一会网线就好使了所以也没处理,直到今天,因为接下来好多 ...

  10. Codeforces Round #551 (Div. 2) E. Serval and Snake (交互题)

    人生第一次交互题ac! 其实比较水 容易发现如果查询的矩阵里面包含一个端点,得到的值是奇数:否则是偶数. 所以只要花2*n次查询每一行和每一列,找出其中查询答案为奇数的行和列,就表示这一行有一个端点. ...