文章目录
-
- acwing 340 通信线路
-
- acwing 341 最优贸易
-
acwing 340 通信线路
![05 算法竞赛进阶指南最短路习题+例题 (附代码+注释+思路)-01_第1张图片](http://img.e-com-net.com/image/info8/d7a6f4350a5d44c1afda63bb8472c1fb.jpg)
题目思路
- 二分做法思路
定义在[0,1000001] 这个区间中的性质如下:
对于区间中的某一个点x。
求出1走到N,最少经过的长度大于x的边的是否小于等于k。
求出从1到N最少经过几条长度大于x的边。
可以将所有的边权分类:大于等于x的为1,小于的为0。
采用双端队列的BFS来求从1到N的最短路。
解题代码
#include
#include
#include
#include
#include
using namespace std;
const int N = 1e3+10,M = 2e5+10;
int h[N],e[M],w[M],ne[M],idx;
int dist[N];
deque<int> q;
bool st[N];
int n,m,k;
bool check(int mid)
{
memset(dist,0x3f,sizeof dist);
memset(st, 0, sizeof st);
dist[1] = 0;
q.push_back(1);
while(!q.empty())
{
int t = q.front(); q.pop_front();
if(st[t]) continue;
st[t] = true;
for(int i=h[t]; ~i; i = ne[i])
{
int j = e[i],v = w[i]>mid;
if(dist[j]>dist[t]+v)
{
dist[j] = dist[t]+v;
if(!v) q.push_front(j);
else q.push_back(j);
}
}
}
if(dist[n]<=k) return true;
return false;
}
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
memset(h, -1, sizeof h);
cin>>n>>m>>k;
for(int i=1; i<=m; i++)
{
int a,b,c; cin>>a>>b>>c;
add(a,b,c); add(b,a,c);
}
int l = 0,r = 1000001;
while(l<r)
{
int mid = l+r >>1;
if(check(mid)) r = mid;
else l = mid+1;
}
if(r==1000001) r = -1;
cout<<r<<"\n";
}
acwing 341 最优贸易
![05 算法竞赛进阶指南最短路习题+例题 (附代码+注释+思路)-01_第2张图片](http://img.e-com-net.com/image/info8/854534686a4c4e4d9492246b4577d925.jpg)
![05 算法竞赛进阶指南最短路习题+例题 (附代码+注释+思路)-01_第3张图片](http://img.e-com-net.com/image/info8/06405953f4e64acb995e92e4e6bff59a.jpg)
题目思路
- 题意思路就是让我们在经过从1到n的道路上,找两个城市间的水晶球差值最大,水晶球价值低的先经过,水晶球价值高的后经过。
- 图中双向通行的道路可以看作两条方向相反的单向通性道路。我们把这张图视为有向图。除此之外,我们还需要建立一张反图(在原图基础上把所有的边的方向取反后的图)保存在另一个邻接表中。
- 先以1为起点,在原图上使用 SPFA 算法,求出一个数组D,其中 D[x] 表示 从节点 1 到节点x的所有路径当中的能够经过的最小的节点权值。D 数组的计算过程和单源最短路径的计算过程类似,只需要把最短路中的用“D[x] + w(x,y) 更新 D[y] ” 改为 “用 min(D[x],price[y]) 更新D[y]”即可,其中 price[y] 表示点y的 商品价格。上面的更新不满足Dijkstra算法的贪心性质,所以要用SPFA算法。
- 再以 n 为起点,在反图上用SPFA算法,求出数组 F,其中F[x] 表示在原图上从x到n的水晶球的最大值。F数组的运算与D数组类似。
- 最后枚举每个节点的x,求出 F[x] - D[x] 的最大值就是我们的答案。
- 因为这道题是随机数据,没有特殊构造,所以可以使用SPFA算法。
解题代码
#include
#include
#include
#include
#include
using namespace std;
const int N = 1e6+10;
int h[N],e[N],ne[N],idx;
int h_fan[N],e_fan[N],ne_fan[N],idx_fan;
int w[N];
int d[N],f[N];
bool st[N];
int n,m;
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void add1(int a,int b)
{
e_fan[idx_fan] = b,ne_fan[idx_fan] = h_fan[a],h_fan[a] = idx_fan++;
}
void spfa(int u)
{
memset(st, 0, sizeof st);
memset(d,0x3f,sizeof d);
queue<int> q; q.push(u); st[u] = true; d[u] = w[u];
while(!q.empty())
{
int t = q.front(); q.pop();
st[t] = false;
for(int i = h[t]; ~i; i=ne[i])
{
int j = e[i];
if(d[j]>min(d[t],w[j]))
{
d[j] = min(d[t],w[j]);
if(!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
}
void spfa1(int u)
{
memset(st, 0, sizeof st);
queue<int> q; q.push(u); st[u] = true; f[u] = w[u];
while(!q.empty())
{
int t = q.front(); q.pop();
st[t] = false;
for(int i = h_fan[t]; ~i; i=ne_fan[i])
{
int j = e_fan[i];
if(f[j]<max(f[t],w[j]))
{
f[j] = max(f[t],w[j]);
if(!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
memset(h, -1, sizeof h);
memset(h_fan, -1, sizeof h_fan);
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>w[i];
for(int i=1; i<=m; i++)
{
int a,b,c; cin>>a>>b>>c;
if(c==1) add(a,b),add1(b,a);
else add(a,b),add(b,a),add1(a,b),add1(b,a);
}
spfa(1);
spfa1(n);
int ans =0;
for(int i=1; i<=n; i++)
{
if(f[i]>d[i]) ans = max(ans,f[i]-d[i]);
}
cout<<ans<<"\n";
return 0;
}