P4568 [JLOI2011]飞行路线
题意:
n个城市,m个航班,你有k次免费坐航班的机会,问从s到t最少花费是多少?
题解:
分层图问题
简单说说什么是分层图:
其实就是将一个平面的图重新建图,有好几层
具体的说每层图之间各自连边与原图一样,但是相邻的两层图之间根据原来的关系进行连边
虽然是多层图,但是用一维的关系就可以
比如:
当有3个点,3层图时
1对应的就是 1+n 和 1+2 * n
2对应的就是 2+n 和 2+2 * n
…
当存在n个点,k层图时,
1对应的就是1+n * 0, 1+ n* 1…1+n * (k-1)
而且每一层的图都遵循只能从上面的图到下一层图,不能反过来
那建这么多层图的目的是什么呢?
你可以理解成是一种尝试,就比如本题,我们向下一层就代表拥有一次免费乘坐的机会,如果我们有k次免费乘坐机会,就建k层图(最原本的是第0层)。
每层图内部是原本的边权关系,而图与图之间是0边权(就相当于是免费乘坐机会)
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){ll s=0,w=1ll;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
void rd_test(){#ifdef ONLINE_JUDGE#elsestartTime = clock(); //计时开始freopen("in.txt","r",stdin);#endif
}
void Time_test(){#ifdef ONLINE_JUDGE#elseendTime = clock(); //计时结束printf("\n运行时间为:%lfs\n",(double)(endTime - startTime) / CLOCKS_PER_SEC);#endif
}
const int maxn=3e5+9;
struct node{int w,now;inline bool operator<(const node &x)const{return w>x.w;}
};
priority_queue<node>q;
int dis[maxn],vis[maxn];
vector<PII>vec[maxn];
int s,t;int n,m,k;
void dijkstra(){memset(dis,INF_int,sizeof(dis));dis[s]=0;q.push((node){0,s});while(!q.empty()){node x=q.top();q.pop();int u=x.now;if(vis[u])continue;vis[u]=1;for(auto it:vec[u]){int v=it.first;int w=it.second;if(dis[v]>dis[u]+w){dis[v]=dis[u]+w;q.push({dis[v],v});}}}
}int main()
{//rd_test();cin>>n>>m>>k;cin>>s>>t;for(int i=1;i<=m;i++){int u,v,w;cin>>u>>v>>w;vec[u].push_back({v,w});vec[v].push_back({u,w});for(int j=1;j<=k;j++){//每一层vec[u+j*n].push_back({v+j*n,w});vec[v+j*n].push_back({u+j*n,w});//层与层之间 vec[u+(j-1)*n].push_back({v+j*n,0});vec[v+(j-1)*n].push_back({u+j*n,0});}}dijkstra();int minn=INF_int;for(int i=0;i<=k;i++){minn=min(minn,dis[t+i*n]);}cout<<minn;return 0;//Time_test();
}