【洛谷】P1938 [USACO09NOV] Job Hunt S(点权转化为边权+跑最长路)好题!

1. 这道题完美地需要我们将点权转成边权:

Bessie 需要去这么多城市,而每座城市他都要赚 D 美元。那我们为什么不直接将每条普通边的边权就设置成 D 呢?这两者之间是等价的呀·····

那对于飞行边来说,同理,飞行边需要花费 T 美元,而到一个城市又可以赚 D 美元,那我们就可以将飞行边权设为 D−T。

这样,存图的事就解决了。

2. 只要你读懂题目,就会发现这题压根不是最短路,是最长路······

做最长路主要有两种做法

2.1 做最短路是我们是现将 dis 数组设为无穷大,再每次更新最小值。反过来,最长路就可以将 dis 数组都设为 0 ,再每次更新最大值。

2.2 将所有边权都取反后,再求最短路(spfa处理负权边)

3:相同的与不同点

相同的:者都是用spfa来做。

不同点,1:最长路是把dis数组初始化为0,负权spfa最短路还是inf

    2:边权不一样最长路存的是add(u,v,d),而最短路存的是add(u,v,-d)

3: 最长路dis[s(起点)]=d,最短路是dis[s(起点)]=-d

4:松弛操作不一样,最长路是if(dis[j]dis[t]+e[i].w)

(-------------------------------------------------------------------------------引用一下大佬的话,言简意赅,适合)

okk分析完毕上ACcode:(这种代码都贴了码哦)

第一种做法:(跑最长路)

#include
using namespace std;
#define int long long 
#define inf 0x3f3f3f3f
const int N=250,M=3500;
struct E{
	int to,w,next;
}e[M];
int head[N],cnt,dis[N],k[N];
bool vis[N];
int d,m,n,f,s,u,v,w,flag;
void add(int u,int v,int w){
	e[++cnt]={v,w,head[u]},head[u]=cnt;
}
void spfa(){
	for(int i=1;i<=n;i++) dis[i]=0;//初始化 
	dis[s]=d;
	queueq;
	q.push(s);
	k[s]++;
	vis[s]=true;
	while(!q.empty()){
		int t=q.front();
		if(++k[t]>n){
			flag=1;
			return;
		}
		q.pop();
		vis[t]=false;
		for(int i=head[t];i;i=e[i].next){
			int j=e[i].to;
			if(dis[j]>d>>m>>n>>f>>s;
   for(int i=1;i<=m;i++){
   	 cin>>u>>v;
   	 add(u,v,d);
   }
   for(int i=1;i<=f;i++){
   	cin>>u>>v>>w;
   	add(u,v,(d-w));
   }
   spfa();
   if(flag){
   	cout<<"-1"<<"\n";
   	return;
   }
   int mmax=-1;
   for(int i=1;i<=n;i++){
   	mmax=max(mmax,dis[i]);
   }
   cout<>tt;
	while(tt--){
		solve();
	}
	return 0;
} 

 

第二种做法(spfa跑负权变最短路) 

#include
using namespace std;
#define int long long 
#define inf 0x3f3f3f3f
const int N=250,M=3500;
struct E{
	int to,w,next;
}e[M];
int head[N],cnt,dis[N],k[N];
bool vis[N];
int d,m,n,f,s,u,v,w,flag;
void add(int u,int v,int w){
	e[++cnt]={v,w,head[u]},head[u]=cnt;
}
void spfa(){
	for(int i=1;i<=n;i++) dis[i]=inf;//初始化 
	dis[s]=-d;
	queueq;
	q.push(s);
	k[s]++;
	vis[s]=true;
	while(!q.empty()){
		int t=q.front();
		if(++k[t]>n){
			flag=1;
			return;
		}
		q.pop();
		vis[t]=false;
		for(int i=head[t];i;i=e[i].next){
			int j=e[i].to;
			if(dis[j]>dis[t]+e[i].w){
				dis[j]=dis[t]+e[i].w;
				if(!vis[j]){
					q.push(j);
					vis[j]=true;
				}
			}
		}
	}
}
void solve(){
   cin>>d>>m>>n>>f>>s;
   for(int i=1;i<=m;i++){
   	 cin>>u>>v;
   	 add(u,v,-d);
   }
   for(int i=1;i<=f;i++){
   	cin>>u>>v>>w;
   	add(u,v,-(d-w));
   }
   spfa();
   if(flag){
   	cout<<"-1"<<"\n";
   	return;
   }
   int mmax=-1;
   for(int i=1;i<=n;i++){
   	mmax=max(mmax,-dis[i]);
   }
   cout<>tt;
	while(tt--){
		solve();
	}
	return 0;
} 

over~

你可能感兴趣的:(算法,c++,图论,点权转化为边权+跑最长路,思维转换)