能力提升綜合題單Part 8.2 最短路問題

1.P5905 【模板】Johnson 全源最短路

利用一個騷勢能公式讓dij可以跑負權圖
思路是先建一個超級源點跟每個點建一條權爲0的邊
跑spfa,有環就退出
然後重新賦上邊權

e[i].w+=h[u]-h[e[i].v];     h是spfa跑出來到每個點的最短路

原理的話oiwiki上講的很清楚
在這裏插入圖片描述
完整代碼:

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=5005,maxm=10005;
struct edge{
	int v,w,nex;
}e[maxm];
struct node{
	int dis,id;
	bool operator<(const node&a)const
	{
		return dis>a.dis;
	}
	node(int d,int x){
		dis=d,id=x;
	}
};
int head[maxn],vis[maxn],cs[maxn];
int cnt,n,m;
long long h[maxn],dis[maxn];
inline void add(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
bool spfa(int s){
	queue<int>q;
	memset(h,63,sizeof(h));
	h[s]=0,vis[s]=1;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			if(h[v]>h[u]+e[i].w){
				h[v]=h[u]+e[i].w;
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
					cs[v]++;
					if(cs[v]==n)return false;
				}
			}
		}
	}
	return true;
}
inline void dij(int s){
	priority_queue<node>q;
	for(int i=1;i<=n;i++)
		dis[i]=inf;
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	q.push(node(0,s));
	while(!q.empty()){
		int u=q.top().id;
		q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				if(!vis[v])q.push(node(dis[v],v));
			}
		}
	}
	return;
}
int main(){
	ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
    }
    for(int i=1;i<=n;i++){
        add(0,i,0);
    }
	if(!spfa(0)){
		cout<<-1<<endl;
		return 0;
	}
	for(int u=1;u<=n;u++)
		for(int i=head[u];i;i=e[i].nex)
			e[i].w+=h[u]-h[e[i].v];
	for(int i=1;i<=n;i++){
		dij(i);
		long long ans=0;
		for(int j=1;j<=n;j++){
			if(dis[j]==inf)ans+=j*inf;
			else ans+=j*(dis[j]+h[j]-h[i]);
		}
		cout<<ans<<endl;
	}
	return 0;
}

2.P1144 最短路計數

給一個無向無權圖,求1到每一點的最短路的條數
bfs+記錄貢獻 無了
如果一個點沒有被訪問過,它的被訪問次序爲前一點的次序+1

if(!vis[t]){
	vis[t]=1;
	tiao[t]=tiao[x]+1;
	q.push(t);
}

如果這個點是距離前一個點最近的點
就加上前一個點的所有路徑數

if(tiao[t]==tiao[x]+1){
		cnt[t]=(cnt[t]+cnt[x])%mod;
	}
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,ans;
const int mod=100003;
struct node{
	int v,w,tiao;
};
vector<int>a[1000005];
int vis[1000005];
int tiao[1000005],cnt[1000005];
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
void bfs(int x){
	
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		x=read();
		y=read();
		a[x].push_back(y);
		a[y].push_back(x);
	}
	memset(vis,0,sizeof(vis));
	queue<int>q;
	q.push(1);
	tiao[1]=0;
	vis[1]=1;
	cnt[1]=1;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int i=0;i<a[x].size();i++){
			int t=a[x][i];
			if(!vis[t]){
				vis[t]=1;
				tiao[t]=tiao[x]+1;
				q.push(t);
			}
			if(tiao[t]==tiao[x]+1){
				cnt[t]=(cnt[t]+cnt[x])%mod;
			}
		}
	}
	for(int i=1;i<=n;i++){
		printf("%d\n",cnt[i]);
	}
	return 0;
}

3. P1462 通往奧格瑞瑪的道路

在血量限制下,最小費用和
二分最大費用跑dij,超過mid的路不能走,血量夠就可以到達終點

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf=0x3f3f3f3f;
int n,m,b,ans,l,r,dis[10005],vis[10005],minn=9999999,maxx=-9999999;
struct node{
	int w,now;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
struct edge{
	int v,w;
};
vector<edge>p[10005],d;
int c[10005];
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
priority_queue<node>q;
inline int dij(int money){
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++){
		dis[i]=inf;
	}
	dis[1]=0;
	q.push((node){0,1});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(c[v]>money)continue;
			if(dis[v]>dis[u]+p[u][i].w){
				dis[v]=dis[u]+p[u][i].w;
				q.push((node){dis[v],v});
			}
		}
	}
	if(dis[n]<=b)return 1;
	else return 0;
}
bool judge(int x){
	if(c[1]>x)return false;
	int tt=dij(x);
	if(tt==1)return true;
	else return false;
}
signed main(){
	n=read(),m=read(),b=read();
	for(int i=1;i<=n;i++){
		c[i]=read();
		minn=min(minn,c[i]);
		maxx=max(maxx,c[i]);
	}
	for(int i=1;i<=m;i++){
		int x,y,z;
		x=read(),y=read(),z=read();
		p[x].push_back((edge){y,z});
		p[y].push_back((edge){x,z});
	}
//	sort(c+1,c+1+n);
	l=minn;
	r=maxx;
	while(l<=r){
		int mid=(l+r)>>1;
		if(judge(mid))r=mid-1,ans++;
		else l=mid+1;
	}
	if(ans==0)cout<<"AFK";
	else cout<<l;
	return 0;
}

4.P1522 [USACO2.4]牛的旅行 Cow Tours

傻逼題
讀了半天才讀懂題意
求連接各個聯通塊的最短路+聯通塊內距離
數據小,Floyd即可

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n;
double mp[200][200],dis[200][200];
struct pos{
	double x,y;
}a[200];
double ltk[200];
double juli(int i,int j){
	return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].x>>a[i].y;
	}
	char t;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>t;
			if(t=='1')dis[i][j]=juli(i,j);
			else if(i!=j)dis[i][j]=inf;
		}
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
	double mi=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(dis[i][j]!=inf){
				ltk[i]=max(ltk[i],dis[i][j]);
			}
			mi=max(mi,ltk[i]);
		}
	}
	double mm=inf;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(dis[i][j]==inf){
				mm=min(mm,ltk[i]+ltk[j]+juli(i,j));
			}
		}
	}
	mm=max(mi,mm);
	printf("%.6f",mm);
	return 0;
} 

5.P1266 速度限制

第一次接觸分層圖最短路
把一維的 dis[i] 換成二維 dis[i][j],i代表到達的點v,j代表速率
跑spfa或dij即可(不卡spfa,用dij保險)

#include<bits/stdc++.h>
using namespace std;
int head[505],cnt;
struct edge{
	int u,v,speed,l,nex;
}e[30005];
struct node{
	int u,speed;
};
inline void add(int u,int v,int speed,int l){
	e[++cnt].v=v;
	e[cnt].speed=speed;
	e[cnt].l=l;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
node pre[505][505];
int inque[505][505],n,m,d;
double dis[505][505];
void pri(int u,int speed){
	if(pre[u][speed].u!=-1)pri(pre[u][speed].u,pre[u][speed].speed);
	printf("%d ",u);
	return;
}
void spfa(){
	for(int i=0;i<=n;i++){
		for(int j=0;j<=505;j++){
			dis[i][j]=9e17;
			pre[i][j].u=pre[i][j].speed=-1;
		}
	}
	queue<node>q;
	q.push((node){0,70});
	inque[0][70]=1;
	dis[0][70]=0;
	while(!q.empty()){
		node x=q.front();
		q.pop();
		int u=x.u;
		int uv=x.speed;
		inque[u][uv]=0;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			int l=e[i].l;
			int vv;
			if(e[i].speed!=0)vv=e[i].speed;
			else vv=uv;
			if(dis[v][vv]>dis[u][uv]+(double)l/vv){
				dis[v][vv]=dis[u][uv]+(double)l/vv;
				pre[v][vv].u=u;
				pre[v][vv].speed=uv;
				if(!inque[v][vv]){
					q.push((node){v,vv});
					inque[v][vv]=1;
				}
			}
		}
	}
}
int main(){
	cin>>n>>m>>d;
	int u,v,w,l;
	for(int i=1;i<=m;i++){
		cin>>u>>v>>w>>l;
		add(u,v,w,l);
	}
	spfa();
	double mm=9e18;
	int mx;
	for(int i=1;i<=505;i++){
		if(mm>dis[d][i]){
			mm=dis[d][i];
			mx=i;
		}
	}
	pri(d,mx);
	return 0;
	
}

6.P4001 [ICPC-Beijing 2006]狼抓兔子

這題原意是要我們會對偶圖…
最大流=最小割=對偶圖最短路
所以我就跑了最大流hhh
細心建圖(一開始讀入假了,還過了三個點)

#include<bits/stdc++.h>
using namespace std;
const int inf =0x3f3f3f3f,maxn=1e6+5,maxm=3e6+5;
int cur[maxn],head[maxn],dep[maxn];
int cnt=1,maxflow=0,n,m,s,t;
struct edge{
	int v,w,nex;
}e[maxm*2];
inline void add_edge(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
	e[++cnt].v=u;
	e[cnt].w=w;
	e[cnt].nex=head[v];
	head[v]=cnt;
}
bool bfs(){
	memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
	dep[s]=1;
	queue<int>q;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			if(!dep[v]&&e[i].w){
				dep[v]=dep[u]+1;
				q.push(v);
				if(v==t)return true;		
			}
		}
	}
	return false;
}
int dfs(int u,int now){
	if(u==t||now==0){
		return now;
	}
	int flow=0,rlow=0;
	for(int i=cur[u];i;i=e[i].nex){
		int v=e[i].v;
		if(e[i].w&&dep[v]==dep[u]+1){
			if(rlow=dfs(v,min(now,e[i].w))){
				flow+=rlow;
				now-=rlow;
				e[i].w-=rlow;
				e[i^1].w+=rlow;
				if(now==0)return flow;
			}
		}
	}
	if(!flow)dep[u]=-1;
	return flow;
}
int dinic(){
	while(bfs()){
		maxflow+=dfs(s,inf);
	}
	return maxflow;
}
int main(){
	scanf("%d%d",&n,&m);
	int u,v,w;
	s=1;
	t=n*m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m-1;j++){
			scanf("%d",&w);
	    	add_edge((i-1)*m+j,(i-1)*m+j+1,w);
		}
	}
	for(int i=1;i<=n-1;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&w);
			add_edge((i-1)*m+j,i*m+j,w);
		}
	}
	for(int i=1;i<=n-1;i++){
		for(int j=1;j<=m-1;j++){
			scanf("%d",&w);
			add_edge((i-1)*m+j,i*m+j+1,w);
		}
	}
//	for(int i=1;i<=n*m;i++){
//		for(int j=head[i];j;j=e[j].nex){
//			printf("%d %d %d\n",i,e[j].v,e[j].w);
//		}
//	}
	printf("%d",dinic());
	return 0;
}

7.P4568 [JLOI2011]飛行路線

分層圖最短路
跟之前那題一樣
第二維代表用了幾次免費,跑dij即可

#include<bits/stdc++.h>
using namespace std;
#define maxn 200010
#define maxm 200010
const int inf=0x3f3f3f3f;
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int v,w;
}e[maxm];
int cnt,n,m,s,vis[maxn][15],dis[maxn][15],k,t;
vector<edge>p[100005];
struct node{
	int w,now,cs;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
priority_queue<node>q;
inline void dij(int s){
	memset(dis,inf,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[s][0]=0;
	q.push((node){0,s,0});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		int cs=x.cs;
		if(vis[u][cs])continue;
		vis[u][cs]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(cs<k&&dis[v][cs+1]>dis[u][cs]){
				dis[v][cs+1]=dis[u][cs];
				q.push((node){dis[v][cs+1],v,cs+1});
			}
			if(dis[v][cs]>dis[u][cs]+p[u][i].w){
				dis[v][cs]=dis[u][cs]+p[u][i].w;
				q.push((node){dis[v][cs],v,cs});
			}
		}
	}
}
signed main(){
	n=read(),m=read(),k=read();
	s=read()+1,t=read()+1;
	for(int i=1,x,y,z;i<=m;i++){
		x=read()+1,y=read()+1,z=read();
		p[x].push_back((edge){y,z});
		p[y].push_back((edge){x,z});
	}
	dij(s);
	int ans=0x7f7f7f7f;
	for(int i=0;i<=k;i++){
		ans=min(ans,dis[t][i]);
	}
	cout<<ans;
	return 0;
}

8.P3238 [HNOI2014]道路堵塞

黑題,咕咕咕待補

9.P5304 [GXOI/GZOI2019]旅行者

黑題,咕咕咕待補

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章