题意:
n n n点 m m m边的图,每条边有边权和颜色,颜色有红蓝白三种,问从 s s s到 t t t恰好走 k 1 k1 k1条红边和 k 2 k2 k2条蓝边的最短距离。
思路:
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示从
s
s
s出发到达点
i
i
i并且经过了
j
j
j条红边,
k
k
k条蓝边的最短距离。
转移就是普通的dijkstra转移,但是这样内存超限。
题目中有一个条件是
k
1
∗
k
2
<
=
800
k1*k2<=800
k1∗k2<=800,如果我们始终把
k
k
k值大的看做是红边,小的看做是蓝边,这样只需要开
455
∗
801
∗
101
455*801*101
455∗801∗101的
d
p
dp
dp数组。
有一个剪枝就是,如果当前经过的红边
>
k
1
>k1
>k1或是蓝边
>
k
2
>k2
>k2,都一定不符合题意了,直接跳过即可,
参考博客
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;typedef unsigned long long ull;
typedef pair<ll,ll>PLL;typedef pair<int,int>PII;typedef pair<double,double>PDD;
#define I_int ll
inline ll read(){ll 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*10+ch-'0';ch=getchar();}return x*f;}
#define read read()
#define rep(i, a, b) for(int i=(a);i<=(b);++i)
#define dep(i, a, b) for(int i=(a);i>=(b);--i)
ll ksm(ll a,ll b,ll p){ll res=1;while(b){if(b&1)res=res*a%p;a=a*a%p;b>>=1;}return res;}
const int maxn=4e5+7,maxm=1e6+7,mod=1e9+7;
int n,m,k1,k2,flag=0,s,t;
struct node{
int e,ne,w,c;
}edge[1100*2];
int h[1100],idx;
ll dp[451][801][101];
struct node1{
ll d,id,t1,t2;
bool operator<(const node1 &a)const{
return d>a.d;
}
};
priority_queue<node1>q;
void add(ll u,ll v,ll w,ll c){
edge[idx]={v,h[u],w,c};h[u]=idx++;
}
void bfs(){
memset(dp,-1,sizeof dp);
dp[s][0][0]=0;
q.push({0,s,0,0});
while(!q.empty()){
node1 t=q.top();q.pop();
ll d=t.d,id=t.id,t1=t.t1,t2=t.t2;
if(t1>k1||t2>k2) continue;
for(int i=h[id];~i;i=edge[i].ne){
int j=edge[i].e,w=edge[i].w,c=edge[i].c;
int now1=0,now2=0;
if(c==1) now1=1;
if(c==2) now2=1;
if(dp[j][t1+now1][t2+now2]==-1||dp[j][t1+now1][t2+now2]>dp[id][t1][t2]+w){
dp[j][t1+now1][t2+now2]=dp[id][t1][t2]+w;
q.push({dp[j][t1+now1][t2+now2],j,t1+now1,t2+now2});
}
}
}
}
int main() {
memset(h,-1,sizeof h);
n=read,m=read,k1=read,k2=read;
if(k1<k2) swap(k1,k2),flag=1;
for(int i=1;i<=m;i++){
ll u=read,v=read,w=read,c=read;
if(flag){
if(c==1) c=2;
else if(c==2) c=1;
}
add(u,v,w,c);
add(v,u,w,c);
}
s=read,t=read;
bfs();
printf("%lld\n",dp[t][k1][k2]);
return 0;
}