从今天开始做最短路!
p4779 迪杰斯特拉模板
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-11;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll cnt,n,m,s,head[2000005],dist[2000005],vis[2000005],pre[2000005];
struct Edge{
ll to,dis,next;
}edge[2000005];
void Add_edge(ll from,ll to,ll w){
edge[++cnt].to=to;
edge[cnt].dis=w;
edge[cnt].next=head[from];
head[from]=cnt;
}
struct node{
ll id,dis;
bool operator<(const node &a)const{
return a.dis<dis;
}
};
void print_path(ll s,ll t){
if(s==t){printf("%lld ",s);return;}
print_path(s,pre[t]);
printf("%d ",t);
}
void dij(){
priority_queue<node>q;
q.push(node{s,0});
for(int i=1;i<=n;i++) dist[i]=inf;
dist[s]=0;
while(!q.empty()){
node a=q.top();q.pop();
ll now=a.id;
if(vis[now]) continue;
vis[now]=1;
for(int i=head[now];i;i=edge[i].next){
ll j=edge[i].to;
if(dist[now]+edge[i].dis<dist[j]){
dist[j]=dist[now]+edge[i].dis;
if(!vis[j]) q.push(node{j,dist[j]});
pre[j]=a.id;
}
}
}
//print_path(s,n);
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld%lld%lld",&n,&m,&s);
for(int i=1;i<=m;i++){
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
Add_edge(a,b,c);
//Add_edge(b,a,c);
}
dij();
for(int i=1;i<=n;i++)
cout<<dist[i]<<" ";
return 0;
}
p1656 无向图求割边 模板
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-11;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll n,m,a,b,head[10005],ct,cnt,low[100005],num[100005],dfn;
struct Edge{
ll to,dis,next;
}edge[100005];
void Add_edge(ll from,ll to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
struct node{
ll s,e;
bool operator<(const node &a)const{
if(a.s==s) return a.e>e;
return a.s>s;
}
}ans[100005];
void dfs(ll u,ll fa){
low[u]=num[u]=++dfn;
for(int i=head[u];i;i=edge[i].next){
ll v=edge[i].to;
if(!num[v]){
dfs(v,u);
low[u]=min(low[v],low[u]);
if(low[v]>num[u]){
if(u>v)ans[++ct].s=v,ans[ct].e=u;
else ans[++ct].s=u,ans[ct].e=v;
}
}
else if(num[v]<num[u]&&v!=fa)
low[u]=min(low[u],num[v]);
}
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++){
scanf("%lld%lld",&a,&b);
Add_edge(a,b);
Add_edge(b,a);
}
dfs(1,-1);
sort(ans+1,ans+ct+1);
for(int i=1;i<=ct;i++)
cout<<ans[i].s<<" "<<ans[i].e<<endl;
return 0;
}
p2648 spfa 超级源
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x3f3f3f3f;
using namespace std;
ll D,P,C,F,S,head[10005],dist[1005],vis[1005],cnt,neg[10005];
struct Edge{
ll to,next,dis;
}edge[10005];
void addedge(ll from,ll to,ll w){
edge[++cnt].to=to;
edge[cnt].dis=w;
edge[cnt].next=head[from];
head[from]=cnt;
}
int spfa(ll s){
memset(neg,0,sizeof(neg));
neg[s]=1;
for(int i=1;i<=C;i++) dist[i]=inf,vis[i]=0;
dist[s]=0;
queue<ll>q;
q.push(S);
vis[s]=1;
while(!q.empty()){
ll u=q.front();q.pop();
vis[u]=0;
for(int i=head[u];i;i=edge[i].next){
ll v=edge[i].to,w=edge[i].dis;
if(dist[u]+w<dist[v]){
dist[v]=dist[u]+w;
if(!vis[v]){
vis[v]=1;
q.push(v);
neg[v]++;
if(neg[v]>=C+1) return 1;//松弛操作最多做n+1次,因为加了个超级源,操作变多
}
}
}
}
return 0;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%lld%lld%lld%lld",&D,&P,&C,&F);
for(int i=1;i<=P;i++){
ll u,v;
scanf("%lld%lld",&u,&v);
addedge(u,v,-D);
}
for(int i=1;i<=F;i++){
ll u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
addedge(u,v,w-D);
}
S=C+1;//增加了超级源,避免每个点都搜一遍
for(int i=1;i<=C;i++) addedge(S,i,0);
int flag=spfa(S);
if(flag){printf("orz");return 0;}
else {
ll minn=inf;
for(int i=1;i<=C;i++){
if(i==S) continue;
minn=min(minn,dist[i]);
}
if(minn>0){cout<<D<<endl;return 0;}
printf("%lld",-1*minn+D);
}
}
p1938 spfa板子
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x3f3f3f3f;
using namespace std;
ll D,P,C,F,S,head[10005],dist[1005],vis[1005],cnt,neg[10005];
struct Edge{
ll to,next,dis;
}edge[10005];
void addedge(ll from,ll to,ll w){
edge[++cnt].to=to;
edge[cnt].dis=w;
edge[cnt].next=head[from];
head[from]=cnt;
}
int spfa(ll s){
memset(neg,0,sizeof(neg));
neg[s]=1;
for(int i=1;i<=C;i++) dist[i]=inf,vis[i]=0;
dist[S]=0;
queue<ll>q;
q.push(S);
vis[S]=1;
while(!q.empty()){
ll u=q.front();q.pop();
vis[u]=0;
for(int i=head[u];i;i=edge[i].next){
ll v=edge[i].to,w=edge[i].dis;
if(dist[u]+w<dist[v]){
dist[v]=dist[u]+w;
if(!vis[v]){
vis[v]=1;
q.push(v);
neg[v]++;
if(neg[v]>=C) return 1;//松弛操作最多做n-1次
}
}
}
}
return 0;
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld%lld%lld%lld%lld",&D,&P,&C,&F,&S);
for(int i=1;i<=P;i++){
ll u,v;
scanf("%lld%lld",&u,&v);
addedge(u,v,-D);
}
for(int i=1;i<=F;i++){
ll u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
addedge(u,v,w-D);
}
int flag=spfa(S);
if(flag){printf("-1");return 0;}
else {
ll minn=inf;
for(int i=1;i<=C;i++){
if(i==S) continue;
minn=min(minn,dist[i]);
}
if(minn>0){cout<<D<<endl;return 0;}
printf("%lld",-1*minn+D);
}
}
p3905 floyd打印路径模板
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,s,t,u[11000],v[11000],path[110][110],w[11000],d,a[11000],b[11000],gra[110][110];
ll vis[110][110];
void floyed(){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(gra[i][j]==inf) path[i][j]=-1;
else path[i][j]=j;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
if(gra[i][k]!=inf)
for(int j=1;j<=n;j++)
if(gra[i][j]>gra[i][k]+gra[k][j]){
gra[i][j]=gra[i][k]+gra[k][j];
path[i][j]=path[i][k];
}
}
int main() {
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) gra[i][j]=0;
else gra[i][j]=inf;
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&u[i],&v[i],&w[i]);
gra[u[i]][v[i]]=w[i];
gra[v[i]][u[i]]=w[i];
}
floyed();
scanf("%lld",&d);
for(int i=1;i<=d;i++) scanf("%lld%lld",&a[i],&b[i]),vis[a[i]][b[i]]=1,vis[b[i]][a[i]]=1;
scanf("%lld%lld",&s,&t);
vector<ll>v;
v.push_back(s);
ll tmp=s;
while(tmp!=t){
v.push_back(path[tmp][t]);
tmp=path[tmp][t];
}
v.push_back(t);
ll sum=0;
for(int i=1;i<v.size();i++){
if(vis[v[i-1]][v[i]])
sum+=gra[v[i-1]][v[i]];
}
printf("%lld",sum);
return 0;
}
p5651 bfs
根据异或的自反性(axor a=0),我们发现,从一个点u抵达另一个点v,不管走那条路,它最后的贡献值都是一样的。所谓的最短路只是一个幌子,其实每两个点的距离就只有唯一解。
题解 P5651 【基础最短路练习题】 - 月离 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,cnt,m,q,head[2000005],dist[2000005],vis[2000005];
struct Edge{
ll to,dis,next;
}edge[2000005];
void addedge(ll from,ll to,ll dis){
edge[++cnt].dis=dis;
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void bfs(ll s){
queue<ll>q;
for(ll i=1;i<=n;i++){
dist[i]=0;vis[i]=0;
}
q.push(s);
while(!q.empty()){
ll now=q.front();q.pop();
if(vis[now]) continue;
vis[now]=1;
for(int i=head[now];i;i=edge[i].next){
ll v=edge[i].to,w=edge[i].dis;
if(!vis[v]){
dist[v]=dist[now]^w;
q.push(v);
}
}
}
}
int main() {
//freopen("in.txt","r",stdin);
scanf("%lld%lld%lld",&n,&m,&q);
for(int i=1;i<=m;i++){
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
bfs(1);
for(int i=1;i<=q;i++){
ll a,b;
scanf("%lld%lld",&a,&b);
printf("%lld\n",dist[a]^dist[b]);
}
return 0;
}
p6464 Floyd
修改其中的一条路径只需要n的二次方就可以了,不需要3次方
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,gra[210][210],g[210][110],a[2100],b[21000],c[21000];
void floyd(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
if(gra[i][k]!=inf)
for(int j=1;j<=n;j++)
if(gra[i][j]>gra[i][k]+gra[k][j])
gra[i][j]=gra[i][k]+gra[k][j];
}
int main() {
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
gra[i][j]=inf;
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
gra[a[i]][b[i]]=c[i];
gra[b[i]][a[i]]=c[i];
}
floyd();
ll minn=inf;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
g[x][y]=gra[x][y];
g[i][j]=g[j][i]=0;
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
if(g[x][y]>g[x][i]+g[i][y])
g[x][y]=g[x][i]+g[i][y];
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
if(g[x][y]>g[x][j]+g[j][y])
g[x][y]=g[x][j]+g[j][y];
ll sum=0;
for(int x=1;x<=n;x++)
for(int y=x+1;y<=n;y++)
if(g[x][y]!=inf)
sum+=g[x][y];
minn=min(minn,sum);
}
printf("%lld",minn);
return 0;
}
p6833 bfs求最短路
求出每个点到这三个地方的最短路径(也就是bfs三遍)然后遍历取最小值就行,ans初始值要大
题解 P6833 【[Cnoi2020]雷雨】 - fanglong 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll dx[4]={-1,1,0,0},dy[4]={0,0,1,-1};
ll n,m,a,b,c,g[1005][1005],dist[3][1005][1005];
struct node{
ll x,y,w;
bool operator<(const node &a)const{
return a.w<w;
}
};
void bfs(ll k,ll sx,ll sy){//计算每个点对该点的最短路
priority_queue<node>q;
q.push(node{sx,sy,g[sx][sy]});
bool vis[1005][1005]={0};
for(int i=1;i<=1000;i++)
for(int j=1;j<=1000;j++) dist[k][i][j]=1e18;
dist[k][sx][sy]=g[sx][sy];
while(!q.empty()){
ll x=q.top().x,y=q.top().y;q.pop();
if(vis[x][y]) continue;
vis[x][y]=1;
for(int i=0;i<4;i++){
ll tx=x+dx[i],ty=y+dy[i];
if(tx<1||tx>n||ty<1||ty>m) continue;
if(dist[k][tx][ty]>dist[k][x][y]+g[tx][ty]){
dist[k][tx][ty]=dist[k][x][y]+g[tx][ty];
q.push(node{tx,ty,dist[k][tx][ty]});
}
}
}
}
int main() {
// freopen("in.txt","r",stdin);
scanf("%lld%lld%lld%lld%lld",&n,&m,&a,&b,&c);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) scanf("%lld",&g[i][j]);
bfs(0,1,a);bfs(1,n,b);bfs(2,n,c);
ll ans=1e18;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=min(ans,dist[0][i][j]+dist[1][i][j]+dist[2][i][j]-2*g[i][j]);
printf("%lld",ans);
return 0;
}
p1073 bfs
题解 P1073 【最优贸易】 - saxiy's blog QωQ。。 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,v[100005],minv[100005],maxv[100005];
ll sa[100005],ans;
queue<ll>q;
struct gra{
ll head[100005],to[1000006],next[1000006],cnt=0;
bool vis[100005];
void addedge(ll u,ll v){
to[++cnt]=v;
next[cnt]=head[u];
head[u]=cnt;
}
void bfs(ll s){
vis[s]=1;q.push(s);
while(!q.empty()){
ll p=q.front();q.pop();
for(int i=head[p];i;i=next[i]){
if(!vis[to[i]])
vis[to[i]]=1,q.push(to[i]);
}
}
}
void mark(ll s,ll *a,ll v){
a[s]=v;q.push(s);
while(!q.empty()){
ll p=q.front();q.pop();
for(int i=head[p];i;i=next[i]){
if(!a[to[i]])
a[to[i]]=v,q.push(to[i]);
}
}
}
}mp,fmp;
bool cmp(ll a,ll b){
return v[a]<v[b];
}
int main() {
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&m);
ll a,b,op;
for(int i=1;i<=n;i++)
scanf("%lld",&v[i]);
while(m--){
scanf("%lld%lld%lld",&a,&b,&op);
mp.addedge(a,b);
fmp.addedge(b,a);
if(op==2){
mp.addedge(b,a);
fmp.addedge(a,b);
}
}
mp.bfs(1);fmp.bfs(n);
for(int i=1;i<=n;i++) sa[i]=i;
sort(sa+1,sa+n+1,cmp);
for(int i=1;i<=n;i++)
if(!minv[sa[i]]&&mp.vis[sa[i]])
mp.mark(sa[i],minv,v[sa[i]]);
for(int i=n;i>=1;i--)
if(!maxv[sa[i]]&&fmp.vis[sa[i]])
fmp.mark(sa[i],maxv,v[sa[i]]);
for(int i=1;i<=n;i++)
if(mp.vis[i]&&fmp.vis[i])
ans=max(ans,maxv[i]-minv[i]);
printf("%lld",ans);
return 0;
}
p1119 floyd
floyd三重循环的第一重是有意义的,是i和j之间允许那几个点作为中转点以使i和j的距离能够更短,那这题不就很好的体现了这个吗,那个村庄建好了,那个就被允许作为中转点了,然后进行一遍转移,之后在看看x,y之间有没有最短的路径就行了
题解 P1119 【灾后重建】 - Time_Rune 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,a[210],u,v,w,q,x,y,t,gra[210][210];
void floyd(ll k){
for(int i=1;i<=n;i++)
if(gra[i][k]!=inf)
for(int j=1;j<=n;j++)
if(gra[i][j]>gra[i][k]+gra[k][j])
gra[i][j]=gra[i][k]+gra[k][j];
}
int main() {
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) gra[i][j]=inf;
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&u,&v,&w);
u++;v++;
gra[u][v]=w;
gra[v][u]=w;
}
scanf("%lld",&q);
ll now=1;
while(q--){
scanf("%lld%lld%lld",&x,&y,&t);
while(a[now]<=t&&now<=n){
floyd(now);
now++;
}
x++;y++;
if(a[x]>t||a[y]>t) printf("-1\n");
else if(gra[x][y]==inf) printf("-1\n");
else printf("%lld\n",gra[x][y]);
}
return 0;
}