首页 > 其他分享 >Living-Dream 系列笔记 第43期

Living-Dream 系列笔记 第43期

时间:2024-03-02 16:58:33浏览次数:24  
标签:Living const int 43 vis push now Dream dis

bellman-ford:

因为最短路最多 \(n\) 点 \(n-1\) 边,则进行 \(n-1\) 轮操作,每轮枚举 \(m\) 边进行松弛即可。

时间复杂度 \(O(nm)\)。

spfa:

正确的称呼是队列优化的 bellman-ford。

我们知道,对于一个点,只有它被松弛了,它的邻接点才有可能被松弛。

于是我们用队列记录可能被松弛的点,每次只对这些点松弛即可。

同时我们用 vis 数组标记已进队的点,放置一个点进队多次。

T1

板子。

//bellman-ford
#include<bits/stdc++.h>
using namespace std;

const int N=1e4+5,M=5e5+5,MOD=1e5+3;
int n,m,s;
int dis[N];
bool vis[N];
struct edge{ int u,v,w; }e[M];

void bellman_ford(int s){
	for(int i=1;i<=n;i++) dis[i]=2147483647;
	dis[s]=0;
	for(int i=1;i<n;i++)
		for(int j=1;j<=m;j++)
			if(dis[e[j].v]-e[j].w>dis[e[j].u])
				dis[e[j].v]=dis[e[j].u]+e[j].w;
}

int main(){
	cin>>n>>m>>s;
	for(int i=1;i<=m;i++)
		cin>>e[i].u>>e[i].v>>e[i].w;
	bellman_ford(s);
	for(int i=1;i<=n;i++) cout<<dis[i]<<' ';
	return 0;	
} 

//spfa
#include<bits/stdc++.h>
using namespace std;

const int N=1e4+5,M=5e5+5,MOD=1e5+3;
int n,m,s;
int dis[N];
bool vis[N];
struct edge{ int v,w; };
vector<edge> G[M];

void spfa(int s){
	for(int i=1;i<=n;i++) dis[i]=2147483647;
	dis[s]=0;
	queue<int> q;
	q.push(s),vis[s]=1;
	while(!q.empty()){
		int now=q.front(); q.pop();
		vis[now]=0;
		for(auto i:G[now]){
			if(dis[i.v]>dis[now]+i.w){
				dis[i.v]=dis[now]+i.w;
				if(!vis[i.v]) vis[i.v]=1,q.push(i.v);
			}
		}
	}
}

int main(){
	cin>>n>>m>>s;
	for(int i=1,u,v,w;i<=m;i++)
		cin>>u>>v>>w,G[u].push_back({v,w});
	spfa(s);
	for(int i=1;i<=n;i++) cout<<dis[i]<<' ';
	return 0;	
} 

T2

加个等待过程即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N=1e5+5,M=1e5+5;
int n,m;
int dis[N];
map<pair<int,int>,bool> o;
bool vis[N];
struct edge{ int v,w; };
vector<edge> G[M];

void spfa(){
	memset(dis,0x3f,sizeof(dis));
	queue<int> q; 
	q.push(1),vis[1]=1,dis[1]=0;
	while(!q.empty()){
		int now=q.front(); q.pop();
		vis[now]=0;
		int nd=dis[now];
		while(o[{now,nd}]) nd++;
		for(auto i:G[now]){
			if(dis[i.v]>nd+i.w){
				dis[i.v]=nd+i.w;
				if(!vis[i.v]) vis[i.v]=1,q.push(i.v);
			}
		}
	}
}

signed main(){
	cin>>n>>m;
	for(int i=1,u,v,w;i<=m;i++)
		cin>>u>>v>>w,G[u].push_back({v,w}),G[v].push_back({u,w});
	for(int i=1,k;i<=n;i++){
		cin>>k;
		for(int j=1,t;j<=k;j++) cin>>t,o[{i,t}]=1;
	}
	spfa();
	cout<<(dis[n]==0x3f3f3f3f3f3f3f3f?-1:dis[n]);
	return 0;	
} 

T3

dijkstra 记录路径并递归输出即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N=1e5+5,M=1e5+5;
int n,m;
int dis[N],path[N];
bool vis[N];
struct edge{ int v,w; };
vector<edge> G[M];
struct node{
	int u,w;
	bool operator < (const node &b) const{
		return w>b.w;
	}
};

void dijkspfa(){
	for(int i=1;i<=n;i++) dis[i]=1e18;
	priority_queue<node> q; 
	q.push({1,0}),dis[1]=0;
	while(!q.empty()){
		node now=q.top(); q.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis[i.v]>dis[now.u]+i.w){
				path[i.v]=now.u;
				dis[i.v]=dis[now.u]+i.w;
				q.push({i.v,dis[i.v]});
			}
		}
	}
}
void print(int x){
	if(x==1){ cout<<x<<' '; return; }
	print(path[x]);
	cout<<x<<' ';
}

signed main(){
	cin>>n>>m;
	for(int i=1,u,v,w;i<=m;i++)
		cin>>u>>v>>w,G[u].push_back({v,w}),G[v].push_back({u,w});
	dijkspfa();
	if(dis[n]==1e18) cout<<-1;
	else print(n);
	return 0;	
} 

作业 T1

跑自己到自己的最长路即可。

#include<bits/stdc++.h>
using namespace std;

const int N=1e4+5,M=5e5+5,MOD=1e5+3;
int n,m,t;
double dis[N];
bool vis[N];
map<string,int> id;
struct edge{ int v; double w; };
vector<edge> G[M];

void spfa(int s){
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++) dis[i]=-1e9;
	dis[s]=1.0;
	queue<int> q;
	q.push(s),vis[s]=1;
	while(!q.empty()){
		int now=q.front(); q.pop();
		vis[now]=0;
		for(auto i:G[now]){
			if(dis[i.v]<dis[now]*i.w){
				dis[i.v]=dis[now]*i.w;
				if(!vis[i.v]) vis[i.v]=1,q.push(i.v);
			}
		}
	}
}

int main(){
	while(cin>>n&&n){
		for(int i=1;i<=n;i++) G[i].clear();
		bool f=0;
		++t;
		for(int i=1;i<=n;i++){
			string s; cin>>s,id[s]=i;
		}
		cin>>m;
		for(int i=1;i<=m;i++){
			string u,v; double w;
			cin>>u>>w>>v,G[id[u]].push_back({id[v],w});
		}
		for(int i=1;i<=n;i++){
			spfa(i);
			if(dis[i]>1.0){
				printf("Case %d: Yes\n",t),f=1;
				break;
			}
		}
		if(!f) printf("Case %d: No\n",t);
	}
	return 0;	
} 

标签:Living,const,int,43,vis,push,now,Dream,dis
From: https://www.cnblogs.com/XOF-0-0/p/18048824

相关文章

  • Living-Dream 系列笔记 第45期
    负环,即负权环,指在图\(G\)中边权和为负数的一回路。负环的判定一般有两种方式。以下均以\(n\)点\(m\)边的图\(G\)为例。法一:以边为研究对象。注意到最短路边数一定不超过\(n-1\)边,因此维护\(cnt_x\)表示起点到\(x\)的边数,若某一时刻存在\(cnt_x>n-1\)则存在......
  • Living-Dream 系列笔记 第42期
    T1枚举流量对于花费跑dijkstra并取比值的\(\max\)即可。关于为什么枚举流量不一定当前最优的问题,因为最优解的流量总在枚举范围内,所以无需考虑当前是否最优。#include<bits/stdc++.h>usingnamespacestd;intn,m,ans;intdis[100031];boolvis[100031];structEdge{......
  • Living-Dream 系列笔记 第44期
    比赛链接T1\(100\to10\)。错因:01背包转移方程写错,没有取\(\max\)。并查集合并错写成将u,v而非fnd(u),fnd(v)合并。#include<bits/stdc++.h>usingnamespacestd;intn,m,w;intc[10031],d[10031];intfa[10031];intdp[10031];intfnd(intx){return......
  • Living-Dream 系列笔记 第41期
    稍微讲一下dijkstraqwq。dijkstra、bellman-ford(orspfa)、bfs的区别:dijkstra以点为研究对象;bellman-ford/spfa则以边为研究对象;而bfs可以看作边权为\(1\)(or全都相同)的dijkstra,因此它可以用队列实现。dijkstra的具体实现:将所有点分为两类(黑点/白点),......
  • Living-Dream 系列笔记 第40期
    T1bf的做法是\(n\)次floyd,实测可以卡过。然后我们发现当点\(u\)为重要点时,当且仅当存在\((a,b)\)使得\(u\)为它们的唯一中转点。于是我们令\(vis_{i,j}\)表示\((i,j)\)的唯一中转点,接着在floyd的松弛操作中若能松弛则更新其为当前中转点\(k\),否则若没有更优......
  • Living-Dream 系列笔记 第39期
    T1一头牛能确定关系,当且仅当它能到达/被到达除自己外的所有牛。于是我们建出有向图,跑floyd传递闭包,然后对于每个点统计他能到达的点数是否为\(n-1\)即可。#include<bits/stdc++.h>usingnamespacestd;intn,m,ans;intdp[131][131];vector<int>G[4531];voidfl......
  • Living-Dream 周考总结 第3期
    Link,第四场没打。T1\(100\),没挂分。\(\operatorname{lcm}(x,y)=\dfrac{x}{\gcd(x,y)}\timesy\)#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){ //freopen("as01.in","r",stdin); //freopen("as0......
  • Living-Dream 周考总结 第4期
    Link。T1\(100\),没挂分。依题计算即可。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){ //freopen("as01.in","r",stdin); //freopen("as01.out","w",stdout); ios::sync_with_stdio(0); ......
  • Living-Dream 周考总结 第1期
    Link。T1依题计算即可,\(O(1)\)。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){ ios::sync_with_stdio(0); doublen;cin>>n,n=ceil(n/5.0); cout<<setprecision(2)<<fixed; if(n<=100)cout<<0.58......
  • Living-Dream 周考总结 第2期
    Link,第二场没打。T1\(100\),没挂分。依题计算即可,\(O(1)\)。#include<bits/stdc++.h>usingnamespacestd;doublen,a,b;intmain(){ //freopen("as01.in","r",stdin); //freopen("as01.out","w",stdout); cin>>n>&......