本题告诉我们:
边上存的信息是很灵活的,除了存边权,还能存各种会影响更新的其他信息
a–(w,b)–>c , b–(w,a)–>c
需要记录在边上的信息不仅包括边权w[i]=max(t[a],t[b]),
还包含与该点配种的植物编号,用g[]存,则更新方式为:
d[j]=min(d[j],max(d[t],d[g[i]])+w[i])
这样就转换为最短路问题了
考虑几个问题
1.能不能用dijk做?
经过验证发现是可行的,因为边权都是正数,每次选取的d最小的点不可能再被其他d比它大的点更新
2.能不能处理有环的情况?
因为求最短路,而各边权为正,不可能存在负环,所以可以处理有环情况,dijk即可
3.能不能用dp做?
dp的思路是记忆化搜索型树形DP
边上存的信息是杂交得到该点的两子节点编号,状态更新:
d[u]=min(d[u],max(t[ee[i].a],t[ee[i].b])+max(dfs(ee[i].a),dfs(ee[i].b)));
因为该图不能保证是树,有可能存在环路,所以不能DP
dijk代码
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int> pii;
const int N=2010,M=2e5+10;
int n,m;
int e[M],ne[M],w[M],idx,h[N],g[M];
int t[N],a[N],cnt,d[N];
bool st[N];
int ed;
void add(int a,int b,int c){//a->c(边上为b)
e[idx]=c,w[idx]=max(t[a],t[b]),g[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dijk(){
priority_queue<pii,vector<pii>,greater<pii>> q;
for(int i=1;i<=cnt;i++){
d[a[i]]=0;
q.push({0,a[i]});
}
while(q.size()){
auto item=q.top();
q.pop();
int t=item.second;
if(st[t])continue;
st[t]=true;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(d[j]>max(d[t],d[g[i]])+w[i]){
d[j]=max(d[t],d[g[i]])+w[i];
q.push({d[j],j});
}
}
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
memset(h,-1,sizeof h);
cin>>n>>cnt>>m>>ed;
for(int i=1;i<=n;i++)cin>>t[i];
for(int i=1;i<=cnt;i++)cin>>a[i];
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
int ans=0x3f3f3f3f;
memset(d,0x3f,sizeof d);
dijk();
cout<<d[ed];
return 0;
}
spfa代码
#include <iostream>
#include <cstring>
using namespace std;
const int N=2010,M=2e5+10;
int n,m;
int e[M],ne[M],w[M],idx,h[N],g[M];
int t[N],a[N],cnt,d[N];
bool st[N];
int ed;
int q[N],hh,tt;
void add(int a,int b,int c){//a->c(边上为b)
e[idx]=c,w[idx]=max(t[a],t[b]),g[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void spfa(){
for(int i=1;i<=cnt;i++){
d[a[i]]=0;
q[tt++]=a[i];
if(tt==N)tt=0;
st[a[i]]=true;
}
while(hh!=tt){
int t=q[hh++];
st[t]=false;
if(hh==N)hh=0;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(d[j]>max(d[t],d[g[i]])+w[i]){
d[j]=max(d[t],d[g[i]])+w[i];
if(!st[j]){
st[j]=true;
q[tt++]=j;
if(tt==N)tt=0;
}
}
}
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
memset(h,-1,sizeof h);
cin>>n>>cnt>>m>>ed;
for(int i=1;i<=n;i++)cin>>t[i];
for(int i=1;i<=cnt;i++)cin>>a[i];
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
int ans=0x3f3f3f3f;
memset(d,0x3f,sizeof d);
spfa();
cout<<d[ed];
return 0;
}
orz
Σ( ° △ °|||)︴
spfa跟你的想法一样就是没确定对不对
膜拜
(^▽^)
six
nb
你是真牛逼啊,佬。双膝下跪QAQ
Σ( ° △ °|||)︴
大佬,我想问一下,如果A和
B杂交能生成C,如果我只有A没有B是不是也能跑出来?
因为边存的是A的可以与B杂交,但是没有去判断
B在不在的问题,所以感觉只有A还是可以求出C
如果b还没有得到,那么d[b]=INF,只是更新d[a]是不会更新d[c]的,相当于考虑了b在不在的问题。
“只有A没有B是不是也能跑出来”你可以试一下
哦哦,理解了,是我疏忽了,没注意到max(d[t],d[g[t]])这个操作,这里就能判断B是否存在了
感谢大佬%%%
(^▽^)
大佬,请问
max(d[t],d[g[i]])
可以理解为这两个原材料(要杂交的两个种子)的 各自最短杂交出来的时间 取最大值,即为准备好这两个原材料的最少时间吗? 是这样理解的吗?QAQ是的,再加上 两者种植所需时间中较大的那个值 就是目标种子被杂交出来最短时间qwq
可是,这样的话我有个疑问,比如a种子杂交出来的时间短,但种植时间长,b种子杂交出来的时间长,但种植时间短。那我可以在a种子杂交出来之后 不等b种子 立即种植,这样ab杂交出来的种子岂不是时间更短,前面算的最短时间就不成立了。QWQ
哇,感觉这似乎是题目的一个bug!按你说的这样做确实能减少很多时间,但是这样题目给的样例就不成立了;如果提前种A,那么最少只要10天就能得到D的种子。所以我觉得这个题的意思是对于A杂交B得到C这个式子,只有在同时得到有A,B两种种子的条件下才会开始种植从而得到C,而不会因为已经得到A或者B就立刻超前种植。不过按你的想法,我觉得转移式子改一下说不定也能做,即d小的那一方的种植时间要减去
d大的那一方和d小那一方的差值,也就是先得到这个种子,然后立刻把它种下去,它的种植时间就要减去这部分了,然后如果减成负数就取0;而且这样的话原做法的边里存的二者种植时间最大值就不对了,因为种植时间不是固定不变的值,所以需要在更新前去计算,这样做不知道对不对qwq
谢谢(●’◡’●)。有点钻牛角尖了,题目的意思应该确实不是这样。
但你这个想法还是很有趣的👍
如果加 虚拟原点, 能ac吗
这建图,高啊
确实很有启发性
%%%
Σ( ° △ °|||)︴
太厉害了
Σ( ° △ °|||)︴
%%学到了很多
(^▽^)
大佬厉害
过奖了,还在路上