[codevs 1391] 伊吹萃香
2016-12-24 17:52
218 查看
题目描述
在幻想乡,伊吹萃香是能够控制物体密度的鬼王。因为能够控制密度,所以萃香能够制造白洞和黑洞,并可以随时改变它们。某一天萃香闲着无聊,在妖怪之山上设置了一些白洞或黑洞,由于引力的影响,给妖怪们带来了很大的麻烦。于是他们决定找出一条消耗体力最少的路,来方便进出。已知妖怪之山上有 N个路口(编号 1..N),每个路口都被萃香设置了一定质量白洞或者黑洞。原本在各个路口之间有 M 条单向路,走过每一条路需要消耗一定量的体力以及 1 个单位的时间。由于白洞和黑洞的存在,走过每条路需要消耗的体力也就产生了变化,假设一条道路两端路口黑白洞的质量差为delta:
1. 从有白洞的路口走向有黑洞的路口,消耗的体力值减少 delta,若该条路径消耗的体力值变为负数的话,取为0。
2. 从有黑洞的路口走向有白洞的路口,消耗的体力值增加 delta。
3. 如果路口两端均为白洞或黑洞,消耗的体力值无变化。
由于光是放置黑洞白洞不足以体现萃香的强大,所以她决定每过 1 个单位时间,就把所有路口的白洞改成黑洞,黑洞改成白洞。当然在走的过程中你可以选择在一个路口上停留 1 个单位的时间,如果当前路口为白洞,则不消耗体力,否则消耗 s[i]的体力。现在请你计算从路口1 走到路口N 最小的体力消耗。保证一定存在道路从路口 1到路口N。
输入格式
第1行:2个正整数N, M第2行:N个整数,第 i个数为0 表示第i个路口开始时为白洞,1 表示黑洞
第3行:N个整数,第 i个数表示第i个路口设置的白洞或黑洞的质量w[i]
第4行:N个整数,第 i个数表示在第 i个路口停留消耗的体力 s[i]
第5..M+4行:每行3 个整数,u, v, k,表示在没有影响的情况下,从路口u走到路口 v需要消
耗k的体力。
输出格式
第1行:1个整数,表示消耗的最小体力样例数据
样例输入
4 51 0 1 0
10 10 100 10
5 20 15 10
1 2 30
2 3 40
1 3 20
1 4 200
3 4 200
样例输出
130样例说明
按照1 -> 3 -> 4的路线。数据范围
对于30%的数据:1 <= N <= 100, 1 <= M <= 500对于60%的数据:1 <= N <= 1,000, 1 <= M <= 5,000
对于100%的数据:1 <= N <= 5,000, 1 <= M <= 30,000
其中20%的数据为1 <= N <= 3000的链
1 <= u,v <= N, 1 <= k,w[i],s[i] <= 200
题目分析
分层图套路:按照范围小的分层这个分层太明显了,明显时间最少,只用保存奇偶性即可
故分别建好时间为奇偶数的图,在奇偶的同一个点连接跨维边,原图的边连向另一层图
然后跑一次SPFA即可
源代码
#include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std; inline const int Get_Int() { int num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; } const int maxn=20005; struct Edge { int from,to,dist; }; struct Spfa { int n,m; vector<Edge>edges; vector<int>G[maxn]; bool inque[maxn]; int dist[maxn],used[maxn],path[maxn]; void init(int n) { this->n=n; edges.clear(); for(int i=1; i<=n; i++)G[i].clear(); } void AddEdge(int from,int to,int dist) { edges.push_back((Edge) { from,to,dist }); m=edges.size(); G[from].push_back(m-1); } bool main(int s) { for(int i=1; i<=n; i++)dist[i]=0x7fffffff/2; memset(inque,0,sizeof(inque)); deque<int>Q; Q.push_back(s); dist[s]=0; path[s]=s; inque[s]=1; used[s]++; while(!Q.empty()) { int Now=Q.front(); Q.pop_front(); inque[Now]=0; for(int i=0; i<G[Now].size(); i++) { Edge& e=edges[G[Now][i]]; int Next=e.to; if(dist[Next]>dist[Now]+e.dist) { dist[Next]=dist[Now]+e.dist; path[Next]=Now; if(!inque[Next]) { used[Next]++; if(used[Next]==edges.size())return false; //负权回环 if(!Q.empty()&&dist[Next]<dist[Q.front()])Q.push_front(Next); //SLF优化 else Q.push_back(Next); inque[Next]=1; } } } } return true; } void Output(int x) { if(path[x]==x) { cout<<x<<" "; return; } Output(path[x]); cout<<x<<" "; } } spfa; //按照时间奇偶性分层 int n,m,Hole[5005],Weight[5005]; int main() { n=Get_Int(); d523 m=Get_Int(); spfa.init(2*n); for(int i=1; i<=n; i++)Hole[i]=Get_Int(); for(int i=1; i<=n; i++)Weight[i]=Get_Int(); for(int i=1; i<=n; i++) { //原地不动 int x=Get_Int(); if(Hole[i]==0) { spfa.AddEdge(i,n+i,0); spfa.AddEdge(n+i,i,x); } else { spfa.AddEdge(i,n+i,x); spfa.AddEdge(n+i,i,0); } } for(int i=1; i<=m; i++) { int x=Get_Int(),y=Get_Int(),v=Get_Int(); int Delta=abs(Weight[x]-Weight[y]); if(Hole[x]==Hole[y]) { spfa.AddEdge(x,n+y,v); spfa.AddEdge(n+x,y,v); } else if(Hole[x]==1&&Hole[y]==0) { //黑->白 spfa.AddEdge(x,n+y,v+Delta); spfa.AddEdge(n+x,y,max(v-Delta,0)); } else { //白->黑 spfa.AddEdge(x,n+y,max(v-Delta,0)); spfa.AddEdge(n+x,y,v+Delta); } } spfa.main(1); printf("%d\n",min(spfa.dist ,spfa.dist[2*n])); return 0; }
相关文章推荐
- codevs 1391 伊吹萃香 分层图spfa
- Codevs 1391 伊吹萃香/虫洞
- 【codevs 1391】伊吹萃香
- 【最短路】codevs 1391 伊吹萃香
- 【codevs 1391】伊吹萃香
- 【codevs 1391】伊吹萃香
- Codevs 1391 伊吹萃香
- [Codevs P1391]伊吹萃香
- codevs 1391 伊吹萃香
- Code vs 1391 伊吹萃香(虫洞)
- [CODEVS P1391]伊吹萃香
- XYLX 10.26 虫洞/Codevs P1391 伊吹萃香
- codevs1391 伊吹萃香
- codevs 1391 伊吹萃香
- [恢]hdu 1391
- codevs 1206 保留两位小数
- 1391: 今年暑假不AC
- [codevs 1961]躲避大龙(dfs)
- codevs 1803 志愿者招募
- 【数论】【筛法求素数】CODEVS 1462 素数和