图的简单入门
debug一天可能是括号的问题。。
推荐使用邻接矩阵存储点少的
开个二维数组[i][j]
i存放入边
推荐使用邻接表点多的存储边 使用vector
先定义一个结构体
node{
int v;//终点编号
int w;//边权重
}
这样vector
加入一个node
node temp;
temp.v=3;
temp.w=4;
v[1].push_back(temp);//这样就插入了一个函数
当然使用c++的类构造函数也是可以
struct Node{
int v,w;
Node(int _v,int _w):v(_v),w(_w){}//这样构造函数
直接v.push_back(Node(3,4));
}
for(int i=1;i<=m;i++){
int u,v,l;
cin>>u>>v>>l;
p[u].push_back((edge){v,l})}
遍历图;
int n,G[max][max]
bool vis[max]={0}
void DFStrave(){
for(int u=0;u<allpeople;u++){//对所有n个顶点进行操作
if(graph[nowvisit][u]>0)//如果能到达,有的时候还得让graph[nowvisit][u]=graph[u][nowvist]=0防止回头
if(vis[u]==false)//如果没有遍历过 进行遍历
//此时一般还会定义一些变量达到对每个连通块**收集信息**效果,
DFS(u,1);//dfs加入了其他的变量参数
//dfs出来后,这些变量就会变成成为**这个连通块**的信息了,使用一些if语句存放处理这个变量
}
}
void dfs(int u,int depth){
vis[u]=true;
for(int v=0;v<=n;v++)//n是顶点数
if(vis[v]==false&&G[u][v]!=INF){//没有访问过并且能从u到达v
DFS(i,depth+1);
}
}
图论,第一步考虑怎么样构建表
1.是否需要将名字转化为编号 int change(string str)//变成了数字才好处理
数据小的时候
map<string ,int >stringtoint //使用map函数来储存,但是如果数据大得用hash
map<int ,string >inttostring
int change (string str){
if(stringtoint.find(str)!=stringtoint.end()){//找一下发现有这个str的记录,返回数字
return map[str];
}
else {
stringtoint[str]=numperson;//新建这个记录等于现在的人数
inttostring[numperson]=str;//两个map都要
return numperson++;//开始初始化的时候设置了numperson为0,为了数组下标考虑,
}
}
数据大的时候
int getid(){
}
2.图的信息点权边权如何输入
是否需要因为指向方向的变化而改变(邻接表)
const int maxn=2010;//最大点数
int G[maxn][maxn]={0};//边权
int weigh[maxn]={0};//点权
for(int i=0;i<n;i++){
cin>>str1>>str2>>w;
int id1=change(str1);
int id2=change(str2) ;
weigh[id1]+=w;
weigh[id2]+=w;
G[id1][id2]+=w;
G[id2][id1]+=w;
}
遍历的时候是否已经是一块连通图,是否只能访问一次
有没有遍历层数的限制(有的话,选用bfs因为dfs可能会导致一次转发次数被重复计算,没有选择dfs)
简单不带权的搜索练习
考题1:连通块计数问题 一般会不给出权值,主要考察普通的搜索
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
vector<int> G[N];//邻接表存边,
bool vis[1005];
int currentpoint;
void dfs(int v){
if(v==currentpoint)//终止条件,下一个删除的点是顶点的时候
return;//
vis[v]=true;
for(int i=0;i<G[v].size();i++){
if(vis[G[v][i]]!=true)
{
dfs(G[v][i]);
}
}
}
int main(){
int n,m,k;
cin>>n>>m>>k;
int x,y;
for(int i=0;i<m;i++){
cin>>x>>y;
G[y].push_back(x);//无向图,两个方向都要
G[x].push_back(y);
}
for(int i=0;i<k;i++){
cin>>currentpoint;
memset(vis,false,sizeof(vis));
int block=0;
for(int i=1;i<=n;i++){//从编号1的点开始搜索到n
if(i!=currentpoint&&!vis[i])//这个点没被删除而且没经过这个点
//上面这里必须要有否则进入了dfs就连通块+1了
{ dfs(i);
block++;
}
}
cout<<block-1<<endl;
}
return 0;
}
forwards on weibo 单向图+单连通块+计算层数(使用node存编号和层数)+对成环的处理(只能转发一次)
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
struct node {
int id;
int layer;
};
vector<int>graph[N];
bool vis[N];
queue<node> q;//单向图+单连通块+计算层数(使用node存编号和层数)+对成环的处理(只能转发一次)
int k,n;
int bfs(int s) {
int nums=0;
node first;//使用node
first.id=s;
first.layer=0;
queue<node>q;
q.push(first);
vis[first.id]=true;
while(!q.empty()) {
node top=q.front();
q.pop();
for(int i=0; i<graph[top.id].size(); i++) {
node next;
next.id=graph[top.id][i];//使用node
next.layer=top.layer+1;
if(vis[next.id]==false&&next.layer<=k) {
q.push(next);
nums++;
vis[next.id]=true;
}
}
}
return nums;
}
int main() {
cin>>n>>k;
for(int i=1; i<=n; i++) {
int person;
int cnt;
cin>>cnt;
for(int j=0; j<cnt; j++) {
cin>>person;
graph[person].push_back(i);
}
}
int ans,askperson;
cin>>ans;
for(int i=0; i<ans; i++) {
cin>>askperson;
memset(vis,false,sizeof(vis));
cout<<bfs(askperson)<<endl;
}
return 0;
}
deepest root 单连通块,判断图是否能转化为树(并查集+n-1),无向图dfs(防止回去),保存最大值,找高度最深的根结点
思路
首先从任意节点出发dfs得到一个最深的叶结点集合A,然后从A集合中任意选一个结点出发dfs得到另一个最深的叶结点集合B,
也就是一开始我并不知道对于一幅图哪个顶点是他的最长跟端点,所以我随便我随便dfs一个点如下面b发现能到达的最长的叶子节点集合里有c和a叶子结点,那么再从c和a中挑一个dfs,就会得到c和e为叶子结点,所以结合a和集合b的交集,都可以作为最长的结点
c
|
a--b-d-e
下面这里第一次选择了g进行dfs获得集合里面有e,从集合任意选择一个即e,dfs找到f
c
|
a--b-d-e
|
g
|
f
#include<bits/stdc++.h>
using namespace std;
const int N=10005;
vector<int> graph[N];
int isfathher[N];
int root[N];
int findfathher(int x){
int a=x;
while(x!=isfathher[x]){
x=isfathher[x];
}
while(a!=isfathher[a]){
int z=a;
isfathher[z]=x;
a=isfathher[a];
}return x;
}
void combine(int x,int y){
int faa=findfathher(x);
int fab=findfathher(y);
if(faa!=fab){
isfathher[faa]=fab;
}
}
void init(int x){
for(int i=1;i<=x;i++){
isfathher[i]=i;
}
}
int calblock(int n){
int block=0;
for(int i=1;i<=n;i++){
root[findfathher(i)]=true;
}
for(int i=1;i<=n;i++){
block+=root[i];
}
return block;
}
//上面全是并查集
int maxheight=0;
vector<int>an,temp;
void dfs(int height,int n,int pre){
if(height>maxheight){
temp.clear();
temp.push_back(n);
maxheight=height;
}
else if(height==maxheight){
temp.push_back(n);
}
for(int i=0;i<graph[n].size();i++){
if(graph[n][i]==pre) continue;//防止回去
dfs(height+1,graph[n][i],n);
}
}
int main(){
int m;
cin>>m;
int x,y;init(m);
for(int i=0;i<m-1;i++)
{
cin>>x>>y;
graph[x].push_back(y);
graph[y].push_back(x);
combine(x,y);
}
int block=calblock(m);
if(block!=1){
printf("Error: %d components",block);
}
else {
dfs(1,1,-1);
an=temp;
dfs(1,an[0],-1);//取已经找出的根节点的任意个结点重新搜
for(int i=0;i<temp.size();i++){
an.push_back(temp[i]);//重新写
}
sort(an.begin(),an.end());
cout<<an[0]<<endl;
for(int i=1;i<an.size();i++){
if(an[i]==an[i-1]) continue;
cout<<an[i] <<endl;
}
}
return 0;
}
----------------------------------------------------------
简单带权的搜索练习
head of a gang 无向图+边权(还需要转成点权)+独立连通块的处理+字符串哈希
一开始以为是无向图,后来发现需要计算一组的边权最大的人,而这个数据必然你打给我,我打给你都要需要算上
一开始用的邻接表存图,发现需要加入点权,而自己又懒得用node结构体,所以改为邻接表
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int n,k;
int numperson=0,t=0,totaltime=0;
map<string ,int >stringtoint;
map<int ,string >inttostring;
int graph[N][N];
int weigh[N];
bool vis[N];
int change(string a){
if(stringtoint.find(a)!=stringtoint.end()){
return stringtoint[a];
}
//不用insert
stringtoint[a]=numperson;//巧妙利用全局变量对人数进行计数
inttostring[numperson]=a;
numperson++;
return numperson-1;
}
map<string,int>gang;//使用string是因为map,自动字典序排序
void dfs(int n,int &head,int &nummember,int &totalvalue){
nummember++;
vis[n]=true;
if(weigh[n]>weigh[head]){
head=n;
}
for(int i=0;i<numperson;i++){
if(graph[n][i]>0){//如果能到达
totalvalue+=graph[n][i];//就算不能从那个点遍历但是还是在图里面所以还是得计算他的边权
graph[n][i]=graph[i][n]=0;//防止重复计算
if(vis[i]==false)//如果没有被访问过就需要进行访问
dfs(i,head,nummember,totalvalue);
}
}
}
void dfstravel(){
for(int i=0;i<numperson;i++){
if(vis[i]==false){
int head=i,nummember=0,totalvalue=0;
dfs(i,head,nummember,totalvalue);
if(nummember>2&&totalvalue>k){
gang[inttostring[head]]=nummember;
}
}
}
}
int main(){
int w;
string a,b;
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>a>>b>>w;
int id1=change(a);
int id2=change(b);
graph[id1][id2]+=w;
graph[id2][id1]+=w;//录入图
weigh[id1]+=w;
weigh[id2]+=w;
}
dfstravel();
cout<<gang.size()<<endl;
map<string ,int >::iterator i;
for(i=gang.begin();i!=gang.end();i++)
cout<<i->first<<" "<<i->second<<endl;
return 0;
}
遍历图里面的点,找到入度为0的点就放入队列
找到入度为0的点,再去找以这个点能到达的点对到达他的入度-1;
map(点,还剩多少入度);
只有剩余为0的点才能进这个队列
最小生成树:让所有的点连在一起而且使得所有边的权值之和最小
k算法(需要并查集)稀疏图
先将图里面所有边的权值排序,由小到大一个个操作
看两侧是不是一个集合,
如果不是 一个集合,要这个边,联合起点和终点合在一起
如果是 跳过
跑无向图的话答案是对的 但是的话边集是少一侧的
p算法(指定哪一个点为起点都可以)稠密图
边解锁了才能走,可以考虑,在所有解锁的边(包括之前操作的不是本点的边)里面选最小的,如果这个边左右两侧没有新结点,就跳过
如果有新结点,放入点集set,解锁他的边
for循环为了 防止树
一个边的集合()
出发点放进set,
for(遍历所有的点){
如果这个点的边没有记录过
就放入这个边的记录
}
while(如果堆不为空){
弹出最小的边
获得这个堆中最小的边的点
如果这个点不在set中即就是没有选过新的点
set添加这个记录
答案增加这条边
然后放入这个点的所有边进入堆
缔结特斯拉(指定一个点告诉你这个图里面所有点的最短距离是多少,到达不了正无穷,权不能为负数的边(可能负值的环最短。。 ))
每次选择到原点最短的点走,走了后解锁从这个点的距离;
通过这个点发现更新的路,发现新的点出现会不会更新记录
使用过就不用,锁死
每一轮,如果 有更小的就更新
表from( 点,距离)
一开始只有一个点
迪杰斯特拉(G,d[],s){
初始化
for(循环n次每个点){
u=使d[u]最小的还未被访问的顶点的标号
记u已经被访问;
for(从u出发能到达的所有顶点v){
if(v未被访问&&以u为中介点使得s到顶点v的最短距离d[v]更优)
优化d[v];
}
}
}
赋初值INF使用fill函数(迭代器初,迭代器末,要填入的数字)
memset是对字节进行操作一般赋值0/1使用
一个表:
对一个点遍历他的所有to点 ,将所有的值记录答案,然后锁住这个点。
然后最这个答案中挑出一个最小的值,以这个点为起点,遍历他的to点,在这个点上加距离,如果比之前的答案记录小就更新这个记录
距离表,存放距离和点
一个哈希表 实现锁每次选择完放进去,set有这个记录就是锁了
遍历距离表 找到距离最小(这个距离最小指的是从源点出发)的而且之前没有操作过的点(哈希表查询),while(有这个点){
遍历他所有的边
找到下一个点tonode
if距离表没有关于tonode的记录
放入这个距离,这个点.距离+边的值
else有这个记录实施能不能更新
min()
遍历完加上这个点的记录
然后在哈希表放入插着记录
}
优化
(系统提供的堆,不能临时改变已经在堆里的值)
自己建造一个堆,能把在里面堆的值并且重新调整
堆需要的功能 update add ingnore(已经排除的结点应该忽略)
在堆上调整logn
怎么往上移动(交换和父亲)
弹出堆中最小的点,然后以这个点为桥梁点看他的to的记录 :如果之前记录没有,加add一个,如果之前有update,如果搞过(-1)就ignore
三个增加考点:
1.增加边权
2.增加点权
3.问多少最短路径多少条
emergency 独立的 点权,最短路数量 问题+
#include<bits/stdc++.h>
using namespace std;
const int N=510;
const int inf=1000000000;
int n,m,st,ed,graph[N][N],weigh[N];//weigh为各个点的点权,这一行记录一般图需要的东西,边权点权
int d[N],w[N],num[N];//w为最大点权之和,d[]为从这个起始点开始到每个点的距离,num表示表示道路的数量
bool vis[N]={false};
void dijkstra(int s){
fill(d, d+N, inf);//一开始从s到所有的点都是无穷大
//memset(num,0, sizeof(num));//所有需要记录的数据要么无穷大,要么设为0;
//memset(w, 0, sizeof(w));//这里如果下面判断的是找最大值就需要设为0,如果找的是最小值就需要设置为inf
d[s]=0;//处理s相关的点
w[s]=weigh[s];//初始赋值s距离,s点权为0,s路径条数为1
num[s]=1;
for(int i=0;i<n;i++){
int current=-1,min=inf;//最小值
for(int j=0;j<n;j++){//第一个for从0到n遍历所有点找最小距离
if(d[j]<min&&vis[j]==false){//如果有最小距离且没有走过,记录这个点
current=j;
min=d[j];
}
}
if(current==-1) return ;//当前待处理的点还是-1,说明剩下的点都无法走,返回
vis[current]=true;//注意选择是这里选择,发现了就立刻标记,下面只是更新
//上面是找距离最小的点所以只需要关注d,下面是需要更新从current点能到的点的值需要使用边权所以用的graph
for(int next=0;next<n;next++){//第二个for从0到n判断每个点是否能更新,注意是每一个点,而不是从当前点到达的某个点
if(graph[current][next]!=inf){//能走话进行判断。。。 如果优化 可以加个条件 如果没有走过才进入下面在进行判断能否更新即vis[next]==false&&
if(d[current]+graph[current][next]<d[next]){//说明前面的记录全部都要改变
d[next]=d[current]+graph[current][next];
w[next]=w[current]+weigh[next];
num[next]=num[current];
}
else if(d[current]+graph[current][next]==d[next]){
if(w[current]+weigh[next]>w[next])
w[next]=w[current]+weigh[next];
num[next]+=num[current];//多出来的道路是从新开发的点找到的点
}
}
}
}
}
int main(){
cin>>n>>m>>st>>ed;
for(int i=0;i<n;i++){
cin>>weigh[i];
}
fill(graph[0],graph[0]+N*N, inf);
for(int i=0;i<m;i++){
int a,b,l;
cin>>a>>b>>l;
graph[a][b]=l;
graph[b][a]=graph[a][b];
}
dijkstra(st);
cout<<num[ed]<<" "<<w[ed];
return 0;
}
travel plan 需要pre记录前驱 并且与上面一题不同的是更新的是小的 所以需要初始话的时候要赋值inf
#include <bits/stdc++.h>
using namespace std;
const int inf=10000000;
const int N=510;
int n,m,st,ed;
int graph[N][N],weigh[N][N];
int d[N],w[N],pre[N];
bool vis[N];
void dijstra(int s){
fill(w,w+N,inf);
fill(d,d+N,inf);
d[s]=0;
w[s]=0;
for(int i=0;i<n;i++){
int current=-1,min=inf;
for(int j=0;j<n;j++){
if(min>d[j]&&vis[j]==false){
min=d[j];
current=j;
}
}
if(current==-1) return ;
vis[current]=true;
for(int next=0;next<n;next++){
if(graph[current][next]!=inf)
if(d[current]+graph[current][next]<d[next]){
d[next]=d[current]+graph[current][next];//距离
w[next]=w[current]+weigh[current][next];//花费
pre[next]=current;//更新前驱
}
else if(d[current]+graph[current][next]==d[next]){
if(w[next]>w[current]+weigh[current][next])
{w[next]=w[current]+weigh[current][next];
pre[next]=current;//更新前驱
}
}
}
}
}
void dfs(int s){//dfs搜索打印前驱,从ed放置
if(s==st)//到了起点就return
{ printf("%d ",st);
return ;
}
dfs(pre[s]);
printf("%d ",s);//注意dfs和打印的顺序
}
int main(){
cin>>n>>m>>st>>ed;
fill(graph[0],graph[0]+N*N,inf);
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
cin>>graph[a][b]>>weigh[a][b];
graph[b][a]=graph[a][b];
weigh[b][a]=weigh[a][b];
}
dijstra(st);
dfs(ed);//放入了终点
cout<<d[ed]<<" "<<w[ed];
}
然而一般都是通过dijkstra+dfs来解决最短路径问题的 核心找前驱
1.使dijkstra记录所有最短路径
2.dfs遍历所有最短的路径,找出以第二标尺为最优的路径
几个概念 多个pre形成的一个棵树,递归终点到了叶子结点就回收
#include <bits/stdc++.h>
using namespace std;
const int inf=10000000;
const int N=510;
int n,m,st,ed;
int graph[N][N],weigh[N][N];
int d[N],w[N];
vector<int>pre[N];//使用前缀数组保存
vector<int>path,temppath;//建立path,temppath存放某一条的路径
bool vis[N];//标记为真
void dijstra(int s){
fill(d,d+N,inf);
d[s]=0;
w[s]=0;
for(int i=0;i<n;i++){
int current=-1,min=inf;
for(int j=0;j<n;j++){
if(min>d[j]&&vis[j]==false){
min=d[j];
current=j;
}
}
if(current==-1) return ;
vis[current]=true;
for(int next=0;next<n;next++){
if(graph[current][next]!=inf)
if(d[current]+graph[current][next]<d[next]){
d[next]=d[current]+graph[current][next];//距离
pre[next].clear();//记得next之前的pre前缀记录都需要清空
pre[next].push_back(current);
}
else if(d[current]+graph[current][next]==d[next]){
pre[next].push_back(current);
}
}
}
}
int mincost=inf;//定义一个全局的变量保存最优
void dfs(int s){
temppath.push_back(s);//进来第一步先把结点存进去temppath,
if(s==st)
{ int cost=0;//定义一个暂时的变量进行处理
for(int i=temppath.size()-1;i>0;i--){//数组从后往前,即路径从开始到后面,
int current=temppath[i],next=temppath[i-1];
cost+=weigh[current][next];
}
if(cost<mincost){//
mincost=cost;
path=temppath;
}
temppath.pop_back();//用完记得回溯
return ;
}
for(int i=0;i<pre[s].size();i++){
dfs(pre[s][i]);
}
temppath.pop_back();//用完记得回溯
}
int main(){
cin>>n>>m>>st>>ed;
fill(graph[0],graph[0]+N*N,inf);
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
cin>>graph[a][b]>>weigh[a][b];
graph[b][a]=graph[a][b];
weigh[b][a]=weigh[a][b];
}
dijstra(st);
dfs(ed);
for(int i=path.size()-1;i>=0;i--){//倒着输出
cout<<path[i]<<" ";
}
cout<<d[ed]<<" "<<mincost;
}
public bike management 无向图+dijkstra+dfs(不是简单相加)+次标尺平均值
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int N=510;
int n,m,cmax,ed,graph[N][N],weigh[N];
int d[N],minneed=inf,minremain=inf;//由题目提示直到需要一个全局变量存储最少解
bool vis[N]={false};
vector<int >pre[N];//
vector<int >path,temppath;
void dijstra(int s){
fill(d,d+N,inf);
d[s]=0;
for(int i=0;i<n;i++){
int u=-1,min=inf;
for(int j=0;j<=n;j++){
if(d[j]<min&&vis[j]==false){
u=j;
min=d[j];
}
}
if(u==-1) return ;
vis[u]=true;
for(int v=0;v<=n;v++){
if(graph[u][v]!=inf&&vis[v]==false)
if(d[v]>d[u]+graph[u][v]){
d[v]=d[u]+graph[u][v];
pre[v].clear();
pre[v].push_back(u);//试过想要输出路径,输出不了原来是这里写错了u为v,直接爆内存
}else if(d[v]==d[u]+graph[u][v]){
pre[v].push_back(u);
}
}
}
}
void dfs(int ed){
temppath.push_back(ed);//进来先放置点
if(ed==0){
int need=0,remain=0;
for(int i=temppath.size()-1;i>=0;i--){
int id=temppath[i];//容易忘了储存当前访问到的结点
if(weigh[id]>0){
remain+=weigh[id];
}
else {
if(remain>abs(weigh[id])){
remain-=abs(weigh[id]);
}else{
need+=abs(weigh[id])-remain;
remain=0;
}
}
}
if(need<minneed){
path=temppath;
minneed=need;
minremain=remain;
}else if(need==minneed&&remain<minremain){
path=temppath;
minneed=need;
minremain=remain;
}
temppath.pop_back();
return ;
}
for(int i=0;i<pre[ed].size();i++){
dfs(pre[ed][i]);
}temppath.pop_back();
}
int main(){
cin>>cmax>>n>>ed>>m;
cmax/=2;
for(int i=1;i<=n;i++){
cin>>weigh[i];
weigh[i]-=cmax;
}
fill(graph[0],graph[0]+N*N,inf);
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
cin>>graph[a][b];
graph[b][a]=graph[a][b];
}
dijstra(0);
dfs(ed);
cout<<minneed<<" ";
for(int i=path.size()-1;i>=0;i--){
cout<<path[i];
if(i>0) cout<<"->";
}
cout<<" "<<minremain;
return 0;
}
gas station
road to roma
#include <bits/stdc++.h>
using namespace std;
const int N=250;
const int inf =1e9;
int n,m,st,ed,graph[N][N],weigh[N];
int d[N],w[N],num[N],pt[N];
bool vis[N];
int pre[N];
//vector<int>pre[N];
vector<int>temppath,path;
map<string ,int >stringtoint ;
map<int, string >inttostring ;
void dijkstra(int s){
fill(d,d+N,inf);
d[s]=0;
w[s]=weigh[st];
num[s]=1;
for(int i=0;i<n;i++){
pre[i]=i;//这里没有初始化会除0,浮点错误
}
for(int i=0;i<n;i++){
int u=-1,min=inf;
for(int j=0;j<n;j++){
if(vis[j]==false &&d[j]<min ){
min=d[j],u=j;
}
}
if(u==-1) return ;
vis[u]=true;
for(int v=0;v<n;v++){
if(graph[u][v]!=inf&&vis[v]==false){
if(d[v]>d[u]+graph[u][v]){
d[v]=graph[u][v]+d[u];
pt[v]=pt[u]+1;
pre[v]=u;
num[v]=num[u];
w[v]=w[u]+weigh[v];
}
else if(d[v]==d[u]+graph[u][v]){
num[v]+=num[u];
if(w[v]<weigh[v]+w[u]){
w[v]=w[u]+weigh[v];
pre[v]=u;
pt[v]=pt[u]+1;
}else if(w[v]==weigh[v]+w[u]){
double uavg=1.0*(w[u]+weigh[v])/(pt[u]+1);
double vavg=1.0*(w[v])/(pt[v]);
if(uavg>vavg){
pre[v]=u;
pt[v]=pt[u]+1;
}
}
}
}
}
}
}
void dfs(int s){
if(s==0){
cout<<inttostring[s];
return ;
}
dfs(pre[s]);
printf("->");
cout<<inttostring[s];
}
int main(){
cin>>n>>m;
string a;
cin>>a;
stringtoint[a]=0;
inttostring[0]=a;
fill(graph[0] ,graph[0]+N*N,inf);
for(int i=1;i<n;i++){
cin>>a>>weigh[i];
stringtoint[a]=i;
inttostring[i]=a;
}
for(int i=0;i<m;i++){
string st1,st2;int s1,s2;cin>>st1>>st2;//这里把st2写成st1 直接寄了
s1=stringtoint[st1],s2=stringtoint[st2];
cin>>graph[s1][s2];
graph[s2][s1]=graph[s1][s2];
}
dijkstra(st);
int ed=stringtoint["ROM"];
cout<<num[ed]<<" "<<d[ed]<<" "<<w[ed]<<" "<<w[ed]/pt[ed]<<endl;
dfs(ed);
return 0;
}
dfs+dijkstra
#include <bits/stdc++.h>
using namespace std;
const int N=250;
const int inf =1e9;
int n,m,st,ed,graph[N][N],weigh[N];
int d[N],w[N],num[N],pt[N];
bool vis[N];
vector<int> pre[N];
//vector<int>pre[N];
vector<int>temppath,path;
map<string ,int >stringtoint ;
map<int, string >inttostring ;
void dijkstra(int s){
fill(d,d+N,inf);
d[s]=0;
w[s]=weigh[st];
num[s]=1;
for(int i=0;i<n;i++){
int u=-1,min=inf;
for(int j=0;j<n;j++){
if(vis[j]==false &&d[j]<min ){
min=d[j],u=j;
}
}
if(u==-1) return ;
vis[u]=true;
for(int v=0;v<n;v++){
if(graph[u][v]!=inf&&vis[v]==false){
if(d[v]>d[u]+graph[u][v]){
d[v]=graph[u][v]+d[u];
pre[v].clear();
pre[v].push_back(u);
}
else if(d[v]==d[u]+graph[u][v]){
pre[v].push_back(u);
}
}
}
}
}
int numpath=0,maxw=0;double maxavg=0;
void dfs(int s){
temppath.push_back(s);
if(s==0){
numpath+=1;
int tempw=0;
double tempavg=0;
for(int i=temppath.size()-1;i>=0;i--){
tempw+=weigh[temppath[i]] ;
}
tempavg=1.0*tempw /(temppath.size()-1);
if(tempw>maxw){
maxw=tempw;
path=temppath;
maxavg=tempavg;
}else if(tempw==maxw){
if(maxavg<tempavg){
maxavg=maxavg;
path=temppath;
}
}
temppath.pop_back();
return ;
}
for(int i=0;i<pre[s].size();i++){
dfs(pre[s][i]);
}
temppath.pop_back();
}
int main(){
cin>>n>>m;
string a;
cin>>a;
stringtoint[a]=0;
inttostring[0]=a;
fill(graph[0] ,graph[0]+N*N,inf);
for(int i=1;i<n;i++){
cin>>a>>weigh[i];
stringtoint[a]=i;
inttostring[i]=a;
}
for(int i=0;i<m;i++){
string st1,st2;int s1,s2;cin>>st1>>st2;//这里把st2写成st1 直接寄了
s1=stringtoint[st1],s2=stringtoint[st2];
cin>>graph[s1][s2];
graph[s2][s1]=graph[s1][s2];
}
dijkstra(st);
int ed=stringtoint["ROM"]; dfs(ed);
cout<<numpath<<" "<<d[ed]<<" "<<maxw<<" "<<(int)maxavg<<endl;
for(int i=path.size()-1;i>=0;i--){
cout<<inttostring[path[i]] ;
if(i>0) cout<<"->" ;
}
return 0;
}
online map
#include <bits/stdc++.h>
using namespace std;
const int N=510;
const int inf =1e9;
int n,m,st,ed,graph[N][N],tm1[N][N];
int d[N],t[N],mintime=inf;
bool visd[N],vist[N];
vector<int> pred[N],pret[N];
//vector<int>pre[N];
vector<int>temppath,patht,pathd;
void dijkstra(int s,int graph[][N],int d[],vector<int>pre[] ,bool vis[]){
fill(d,d+N,inf);
d[s]=0;
for(int i=0;i<n;i++){
int u=-1,min=inf;
for(int j=0;j<n;j++){
if(vis[j]==false &&d[j]<min ){
min=d[j],u=j;
}
}
if(u==-1) return ;
vis[u]=true;
for(int v=0;v<n;v++){
if(graph[u][v]!=inf&&vis[v]==false){
if(d[v]>d[u]+graph[u][v]){
d[v]=graph[u][v]+d[u];
pre[v].clear();
pre[v].push_back(u);
}
else if(d[v]==d[u]+graph[u][v]){
pre[v].push_back(u);
}
}
}
}
}
int numpath=0,maxw=0;double maxavg=0;
void getd(){
int temptime=0;
for(int i=temppath.size()-1;i>0;i--){
temptime+=tm1[temppath[i]][temppath[i-1]];
}
if(temptime<mintime){
mintime=temptime;
pathd=temppath;
}
}
void gett(){
if(patht.size()==0||temppath.size()<patht.size()){
patht=temppath;//最有路径为空,或者找到了顶点个数更小的路
// cout<<"path长度等于"<<temppath.size();
}
}
void dfs(int v,vector<int>pre[],bool isfirstpath){
temppath.push_back(v);
if(v==st ){
if(isfirstpath) getd();
else gett();
temppath.pop_back();//这里忘记了pop 所以输出了两个终点答案
return ;
}
for(int i=0;i<pre[v].size();i++){
dfs(pre[v][i],pre,isfirstpath);
}
temppath.pop_back();
}
void printfpath(vector<int>path){
cout<<path.back();
for(int i=path.size()-2;i>=0;i--){
cout<<" -> "<<path[i];
}cout<<endl;
}
int main(){
cin>>n>>m;
int a,b,oneway;
fill(graph[0], graph[0]+N*N,inf );
fill(tm1[0],tm1[0]+N*N,inf);
for(int i=0;i<m;i++){
cin>>a>>b>>oneway;//0是双向
cin>>graph[a][b];
cin>>tm1[a][b];
if(oneway==0){
graph[b][a]=graph[a][b];
tm1[b][a]=tm1[a][b];
}
}
cin>>st>>ed;
dijkstra(st,graph,d,pred,visd);
dijkstra(st,tm1,t,pret,vist);
int c=ed;
dfs(ed,pred,1);
dfs(ed,pret,0);
cout<<"Distance = "<<d[ed];
if(pathd==patht) cout<<"; ";
else {
cout<<": ";
printfpath(pathd);
}
printf("Time = %d: ",t[ed]);
// patht.pop_back();
printfpath(patht);
return 0;
}
bellman算法
由于dijstra一开始需要选择dsit最小的点作为选择,如果此时出现的边不是最优选择的话(因为别的路线可能有一个很大的赋值,掩盖了第一次选择的问题),