「NOIP2009」最優貿易 題解 (最短路SPFA)
阿新 • • 發佈:2021-11-08
題目簡介
分析
這道題有多種方法可以實現,我選用的是相對簡單的兩遍\(SPFA\)
看到網上的題解大多都是兩個鄰接表陣列,兩個存邊函式,兩個計算函式,我有些沾沾自喜。
將圖封裝在結構體中,就是香呀~
使用圖 \(a\) 存從 \(1\) 到 \(i\) 的最小進口價格,圖 \(b\) 存從 \(i\) 到 \(n\) 的最大出口價格,再遍歷一遍 i ,最終答案就是
\[max\{b.D(i)-a.D(i)\} \]帶你設計結構體 \(Edge\)
struct Edge{
....
}a,b;
結構體 \(Edge\)
1.鏈式前向星(鄰接表)存邊
struct edge_node{ int nxt,to; }e[Maxn]; int head[maxn]; int tot; inline void add(int u,int v){ e[++tot].nxt=head[u]; e[tot].to=v; head[u]=tot; }
int x,y,z;
for(int i=1;i<=m;i++){
x=read();y=read();z=read();
a.add(x,y),
b.add(y,x);
if(!(z&1))
a.add(y,x),
b.add(x,y);
}
2.\(SPFA\)
這裡開始值得注意了。
在 main()
函式中,我們的呼叫方法是:
a.spfa(1,1);
b.spfa(n,0);
所以此函式的定義方法是:
void spfa(int s,bool cmp)
\(cmp\) 表示的是求解 \(D\) 的方法,\(false\)表示求最小值,\(true\)
自然地,\(s\) 表示的是起點位置。
\(SPFA\) 的轉移條件本來是:
\[D[y]=max/min\{D[x]+dis[y]\} \]這裡應題目需要改成:
\[D[y]=max/min\{max/min\{D[x],price[y]\}\} \]inline void spfa(int s,bool cmp){ if(cmp)memset(d,0x3f,sizeof(d)); queue<int>q; d[s]=price[s]; v[s]=true; q.push(s); while(!q.empty()){ int x=q.front(); q.pop(); v[x]=false; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; int z; if(cmp)z=mymin(d[x],price[y]); else z=mymax(d[x],price[y]); if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){ d[y]=z; if(!v[y]) q.push(y), v[y]=true; } } } }
\(AC\) 程式碼
如果你久久過不了本題,請看完整程式碼吧:
裸\(SPFA\):
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int Maxn=maxn<<1;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline int mymax(int a,int b){return a>b?a:b;}
inline int mymin(int a,int b){return a<b?a:b;}
int price[maxn];
struct Edge{
struct edge_node{
int nxt,to;
}e[Maxn];
int head[maxn];
int tot;
inline void add(int u,int v){
e[++tot].nxt=head[u];
e[tot].to=v;
head[u]=tot;
}
int d[maxn];
bool v[maxn];
inline void spfa(int s,bool cmp){
if(cmp)memset(d,0x3f,sizeof(d));
queue<int>q;
d[s]=price[s];
v[s]=true;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
v[x]=false;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
int z;
if(cmp)z=mymin(d[x],price[y]);
else z=mymax(d[x],price[y]);
if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){
d[y]=z;
if(!v[y])
q.push(y),
v[y]=true;
}
}
}
}
}a,b;
int n,m;
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)price[i]=read();
int x,y,z;
for(int i=1;i<=m;i++){
x=read();y=read();z=read();
a.add(x,y),
b.add(y,x);
if(!(z&1))
a.add(y,x),
b.add(x,y);
}
a.spfa(1,1);
b.spfa(n,0);
int ans=0;
for(int i=1;i<=n;i++){
ans=mymax(ans,b.d[i]-a.d[i]);
}
printf("%d\n",ans);
return 0;
}
由於沒有負權環,可以考慮使用更穩定的堆優化,雖然對於本題沒有裸 \(SPFA\) 快:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int Maxn=maxn<<1;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline int mymax(int a,int b){return a>b?a:b;}
inline int mymin(int a,int b){return a<b?a:b;}
int price[maxn];
struct Edge{
struct edge_node{
int nxt,to;
}e[Maxn];
int head[maxn];
int tot;
inline void add(int u,int v){
e[++tot].nxt=head[u];
e[tot].to=v;
head[u]=tot;
}
int d[maxn];
bool v[maxn];
inline void spfa(int s,bool cmp){
if(cmp)memset(d,0x3f,sizeof(d));
priority_queue<pair<int,int> >q;
d[s]=price[s];
v[s]=true;
q.push(make_pair(-d[s],s));
while(!q.empty()){
int x=q.top().second;
q.pop();
v[x]=false;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
int z;
if(cmp)z=mymin(d[x],price[y]);
else z=mymax(d[x],price[y]);
if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){
d[y]=z;
if(!v[y])
q.push(make_pair(-d[y],y)),
v[y]=true;
}
}
}
}
}a,b;
int n,m;
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)price[i]=read();
int x,y,z;
for(int i=1;i<=m;i++){
x=read();y=read();z=read();
a.add(x,y),
b.add(y,x);
if(!(z&1))
a.add(y,x),
b.add(x,y);
}
a.spfa(1,1);
b.spfa(n,0);
int ans=0;
for(int i=1;i<=n;i++){
ans=mymax(ans,b.d[i]-a.d[i]);
}
printf("%d\n",ans);
return 0;
}
本題較為良心,不卡 \(SPFA\) ,出於謹慎,可以加一個 \(SLF\) 優化:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int Maxn=maxn<<1;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline int mymax(int a,int b){return a>b?a:b;}
inline int mymin(int a,int b){return a<b?a:b;}
int price[maxn];
struct Edge{
struct edge_node{
int nxt,to;
}e[Maxn];
int head[maxn];
int tot;
inline void add(int u,int v){
e[++tot].nxt=head[u];
e[tot].to=v;
head[u]=tot;
}
int d[maxn];
bool v[maxn];
inline void spfa_slf(int s,bool cmp){
if(cmp)memset(d,0x3f,sizeof(d));
deque<int>q;
d[s]=price[s];
v[s]=true;
q.push_back(s);
while(!q.empty()){
int x=q.front();
q.pop_front();
v[x]=false;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
int z;
if(cmp)z=mymin(d[x],price[y]);
else z=mymax(d[x],price[y]);
if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){
d[y]=z;
if(!v[y]){
v[y]=true;
if(q.empty()||d[y]>d[q.front()])
q.push_back(y);
else q.push_front(y);
}
}
}
}
}
}a,b;
int n,m;
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)price[i]=read();
int x,y,z;
for(int i=1;i<=m;i++){
x=read();y=read();z=read();
a.add(x,y),
b.add(y,x);
if(!(z&1))
a.add(y,x),
b.add(x,y);
}
a.spfa_slf(1,1);
b.spfa_slf(n,0);
int ans=0;
for(int i=1;i<=n;i++){
ans=mymax(ans,b.d[i]-a.d[i]);
}
printf("%d\n",ans);
return 0;
}