分层图食用简介
N个虫洞,M条单向跃迁路径。从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间。虫洞有白洞和黑洞之分。设一条跃迁路径两端的虫洞质量差为delta。
1.从白洞跃迁到黑洞,消耗的燃料值减少delta,若该条路径消耗的燃料值变为负数的话,取为0。
2.从黑洞跃迁到白洞,消耗的燃料值增加delta。
3.路径两端均为黑洞或白洞,消耗的燃料值不变化。
作为压轴题,自然不会是如此简单的最短路问题,所以每过1单位时间黑洞变为白洞,白洞变为黑洞。在飞行过程中,可以选择在一个虫洞停留1个单位时间,如果当前为白洞,则不消耗燃料,否则消耗s[i]的燃料。现在请你求出从虫洞1到N最少的燃料消耗,保证一定存在1到N的路线。
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。
第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。
输出
一个整数,表示最少的燃料消耗。
样例输入 Copy
4 5
1 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
样例输出 Copy
130
提示
样例解释:
按照1->3->4的路线。
对于30%的数据: 1<=N<=100,1<=M<=500
对于60%的数据: 1<=N<=1000,1<=M<=5000
对于100%的数据: 1<=N<=5000,1<=M<=30000 ,其中20%的数据为1<=N<=3000的链 1<=u,v<=N, 1<=k,w[i],s[i]<=200
按照1->3->4的路线。
对于30%的数据: 1<=N<=100,1<=M<=500
对于60%的数据: 1<=N<=1000,1<=M<=5000
对于100%的数据: 1<=N<=5000,1<=M<=30000 ,其中20%的数据为1<=N<=3000的链 1<=u,v<=N, 1<=k,w[i],s[i]<=200
解法:dp,分层图。
个人dp较弱,还没调出来,于是强行建图跑dijkspa喽...
dijkspa万岁!
(其实只是spfa)
个人认为分层图的精髓就在于+n建图,有些类似种群并查集吧。考场上因为没有+n,所以崩溃了...
#include<bits/stdc++.h> using namespace std; const int maxn=50005; int h[maxn],w[maxn],o[maxn]; int n,m; struct edge { int dis,to,next; }e[maxn<<2]; int head[maxn],cnt; inline void addedge(int from,int to,int dis) { e[++cnt].next=head[from]; e[cnt].to=to; e[cnt].dis=dis; head[from]=cnt; } void add() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&h[i]); } for(int i=1;i<=n;i++) { scanf("%d",&w[i]); } for(int i=1;i<=n;i++) { scanf("%d",&o[i]); } for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if(h[x]==h[y])//如果颜色一样的两点,不额外耗费燃料,所以在两点间建一个原边,分层,在上下两层的点之间建边 { addedge(x,y+n,z);//坑逼建图 addedge(x+n,y,z); } else { int delta=abs(w[x]-w[y]); addedge(x+n,y+n,z+delta);//不一样,黑白之间建边 addedge(x,y,max(z-delta,0)); } } for(int i=1;i<=n;i++) { addedge(i,i+n,0);//在黑白点之间建立转化点 addedge(i+n,i,o[i]); } } int dis[maxn],vis[maxn]; struct cmp { bool operator() (int a,int b) { return dis[a]>dis[b]; } }; priority_queue< int , vector < int > , cmp > q; void dijkspa() { int s=1;//这里,起点也许就要等待,所以需要特判一发,被坑了2个点... if(h[1]==1) s=n+1; for(int i=1;i<=2*n;i++) { dis[i]=0x7fffffff; vis[i]=0; } q.push(s); vis[s]=1; dis[s]=0; while(!q.empty()) { int u=q.top(); q.pop(); vis[u]=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(dis[v]>dis[u]+e[i].dis) { dis[v]=dis[u]+e[i].dis; if(vis[v]==0) { q.push(v); vis[v]=1; } } } } } int main() { add(); dijkspa(); printf("%d",min(dis[n],dis[n+n]));//终点是黑是白不确定,所以也要比较。 return 0; }
(完)