パスには特定の要件があることを見て、階層内の最短パスを考えます。
階層化の最短経路を考えるときは、変革に注意を払い、一直線に考えないでください。
対象の特殊操作を四方八方で実行できる簡単な操作に変換し、DPの設計により対象の要件を実現します。
CF1473Eでは、タイトルに「パス」と表示され、最大のエッジと最小のエッジが削除されます。DPを設計する場合、dp [i] [0/1] [0/1]はポイントiでのパスの合計を表し、1/0はこの場合のプラス/マイナスエッジとしてエッジが選択されているかどうかを表します。私たちが操作するとき、減算は最大ではなく、加算は最小ではないかもしれませんが、DPの転送を通じて、最適な状況は間違いなく私たちによって計算されます。
トピックの特殊性にも注意してください。パスはエッジから任意に減算できます。これにより、最大の辺と最小の辺のパスが明らかに減算されます。パスは、エッジに任意に追加でき、明らかに、のパスが追加されます。最小の辺と最小。次に、各パスの最小値プラス1マイナス1辺は、明らかにタイトルで定義されたパスの長さです。
タイトルでは、最大値を減算し、最小値を加算する必要があります。これは、各側の減算または加算に変換されます。遷移の値は、エッジの重みの最小の合計です。
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <stack>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--)
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define sci(x) scanf("%d",&(x))
#define scl(x) scanf("%lld",&(x))
#define scs(x) scanf("%s",(x))
#define pri(x) printf("%d\n",(x))
#define prl(x) printf("%lld\n",(x))
#define prs(x) printf("%s\n",(x))
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define All(x) x.begin(),x.end()
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--)
using namespace std;
typedef long long ll;
typedef double db;
const int N=2e5+5;
const int mod=10007;
const db eps=1e-6;
const db pi=acos(-1.0);
int n,m,vis[N][2][2];
struct edge{
int v;
ll w;
};
vector<edge>tr[N];
struct E{
int v,x,y;
ll dis;
bool operator < (const E &A)const{
return dis>A.dis;
}
};
priority_queue<E>q;
ll dis[N][2][2];
int main(){
#ifndef ONLINE_JUDGE
freopen("D:\\work\\data.in","r",stdin);
#endif
cin>>n>>m;
rep(i,1,m){
int u,v;
ll w;
cin>>u>>v>>w;
tr[u].push_back({v,w});
tr[v].push_back({u,w});
}
ms(dis,INFF);
q.push({1,0,0,0});
dis[1][0][0]=0;
while(q.size()){
E tmp=q.top();
q.pop();
if(vis[tmp.v][tmp.x][tmp.y]) continue;
vis[tmp.v][tmp.x][tmp.y]=1;
ll curdis=tmp.dis;
for(auto v:tr[tmp.v]){
ll *d=&dis[v.v][tmp.x][tmp.y];
if(curdis+v.w<*d){
*d=curdis+v.w;
q.push({v.v,tmp.x,tmp.y,*d});
}
d=&dis[v.v][1][tmp.y];
if(tmp.x==0&&curdis<*d){
*d=curdis;
q.push({v.v,1,tmp.y,*d});
}
d=&dis[v.v][tmp.x][1];
if(tmp.y==0&&curdis+2LL*v.w<*d){
*d=curdis+2LL*v.w;
q.push({v.v,tmp.x,1,*d});
}
d=&dis[v.v][1][1];
if(tmp.x==0&&tmp.y==0&&curdis+v.w<*d){
*d=curdis+v.w;
q.push({v.v,1,1,*d});
}
}
}
rep(i,2,n){
cout<<dis[i][1][1]<<" ";
}
}
POJ3662では、この問題により、パスのk +1エッジをできるだけ小さくする必要があります。ただし、DPを設計する場合、dp [i] [j]は、j個のエッジの最大自由エッジ重みが点iで指定されていることを意味します。ポイントiへのパスでj番目に大きいエッジを表すのではなく。前者の場合、必ずしもjが最大のエッジであるとは限らない自由なjエッジを設定できますが、状態遷移を通じて最適な状況が確実に得られます。後者を使用すると、状態遷移方程式は明らかに次のようにはなりません。前者のように単純です。
パスごとに、選択できるk個のフリーパスは異なりますが、最初のKが大きい場合に残っている最大のエッジである必要があることが理解できます。次に、各パスによって残された最大のエッジを比較して、答えを取得します。
この問題では、最初のKのみが取り出されてから、任意のKエッジを取るように変換される必要があります。転送された値は、残りの最大エッジウェイトです。
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <stack>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--)
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define sci(x) scanf("%d",&(x))
#define scl(x) scanf("%lld",&(x))
#define scs(x) scanf("%s",(x))
#define pri(x) printf("%d\n",(x))
#define prl(x) printf("%lld\n",(x))
#define prs(x) printf("%s\n",(x))
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define All(x) x.begin(),x.end()
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--)
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e3+5;
const int mod=1e9+7;
const db eps=1e-6;
const db pi=acos(-1.0);
int n,p,k,vis[N][N],dis[N][N];
struct edge{
int v,w;
};
vector<edge>tr[N];
struct E{
int v,k,w;
bool operator < (const E &A) const{
return w>A.w;
}
};
priority_queue<E>q;
void upd(int tmp,int v,int nx){
if(tmp<dis[v][nx]){
dis[v][nx]=tmp;
q.push({v,nx,tmp});
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("D:\\work\\data.in","r",stdin);
#endif
ms(dis,INF);
cin>>n>>p>>k;
rep(i,1,p){
int u,v,w;
cin>>u>>v>>w;
tr[u].push_back({v,w});
tr[v].push_back({u,w});
}
q.push({1,0,0});
while(q.size()){
E tmp=q.top();
q.pop();
if(vis[tmp.v][tmp.k]) continue;
vis[tmp.v][tmp.k]=1;
repp(i,0,tr[tmp.v].size()){
edge e=tr[tmp.v][i];
if(tmp.k<=k) upd(tmp.w,e.v,tmp.k+1);
upd(max(e.w,tmp.w),e.v,tmp.k);
}
}
cout<<(dis[n][k]==INF?-1:dis[n][k])<<endl;
}
最大値と最小値が必要なため、バイナリ回答を使用できます。midより大きいエッジの重みは1に設定され、mid以下のエッジの重みは0に設定されます。この01ダイアグラムは、両端キューBFAを使用して最短パスを見つけるために使用できます。最終的にdis [n]> kの場合、midよりも大きいエッジがkを超えており、midが小さすぎることを意味します。それ以外の場合は、大きすぎます。
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <stack>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--)
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define sci(x) scanf("%d",&(x))
#define scl(x) scanf("%lld",&(x))
#define scs(x) scanf("%s",(x))
#define pri(x) printf("%d\n",(x))
#define prl(x) printf("%lld\n",(x))
#define prs(x) printf("%s\n",(x))
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define All(x) x.begin(),x.end()
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--)
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e3+5;
const int mod=1e9+7;
const db eps=1e-6;
const db pi=acos(-1.0);
int n,m,w[N][N],p,k,u,v,vis[N],dis[N];
int main(){
#ifndef ONLINE_JUDGE
freopen("D:\\work\\data.in","r",stdin);
#endif
ms(w,INF);
cin>>n>>p>>k;
rep(i,1,p){
cin>>u>>v;
cin>>w[u][v];
w[v][u]=w[u][v];
}
int l=0,r=INF,flag=1;
while(l<r){
int mid=(l+r)>>1;
rep(i,1,n) vis[i]=0,dis[i]=INF;
deque<int>de;
de.push_back(1);
dis[1]=0;
while(de.size()){
int tmp=de.front();
de.pop_front();
if(vis[tmp]) continue;
vis[tmp]=1;
rep(i,1,n){
if(w[tmp][i]==INF) continue;
if(w[tmp][i]>mid&&dis[i]>dis[tmp]+1){
dis[i]=dis[tmp]+1;
de.push_back(i);
}
if(w[tmp][i]<=mid&&dis[i]>dis[tmp]){
dis[i]=dis[tmp];
de.push_front(i);
}
}
}
if(dis[n]==INF){
flag=0;
break;
}else if(dis[n]>k) l=mid+1;
else r=mid;
}
cout<<(flag?l:-1)<<endl;
}