nyoj 247 虚拟城市之旅 路径压缩
虚拟的城市之旅
时间限制:3000 ms | 内存限制:65535 KB
难度:6
- 描述
-
展馆是未来城市的缩影,个人体验和互动是不变的主题。在A国展馆通过多维模式和高科技手段,引领参观者在展示空间踏上一段虚拟的城市之旅。梦幻国有N个城市和M条道路,每条道路连接某两个城市。任意两个城市之间最多只有一条道路直接相连。这M条道路中有一部分为单向通行的道路,一部分为双向通行的道路。梦幻国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。现在你已踏上一段虚拟的城市之旅。为了给你一个意外收获,允许你在旅游的同时,利用 X 商品在不同城市中的差价赚回一点旅费,但最多只能交易一次。即,在某个城市买入X 商品,可以走到另外一个城市买掉来获得旅费。当然,在赚不到差价的情况下,你也可以不进行贸易活动。设梦幻国N个城市的标号从1~ N,你只能从1 号城市出发,并最终在N 号城市结束自己的旅行。在旅游的过程中,任何城市可以重复经过多次,但不要求经过所有N个城市。例如:梦幻国有5个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路为单向通行,双向箭头表示这条道路为双向通行。假设 X 商品在1~5 号城市的价格分别为 4,3,5,6,1。你可以选择如下一条线路:1235,并在2 号城市以3 的价格买入X 商品,在3号城市以5 的价格卖出X 商品,赚取的旅费数为2。你也可以选择如下一条线路14545,并在第1次到达5号城市时以1的价格买入X 商品,在第2次到达4号城市时以6 的价格卖出X 商品,赚取的旅费数为5。现在给出N个城市的X 商品价格,M条道路的信息(每条道路所连接的两个城市的编号以及该条道路的通行情况)。请问你能赚取尽可能多的旅费吗。
- 输入
- 有多组测试数据(以EOF为文件结束的标志)
每组测试数据的格式如下:
第一行:N M 分别表示城市的数目和道路的数目。
第二行:N个正整数,每两个整数之间用一个空格隔开,分别表示1到N个城市的商品价格。
接下来 M行,每行有3个正整数,X,Y,Z,每两个整数之间用一个空格隔开。
如果 Z=1,表示这条道路是城市X到城市Y之间的单向道路;
如果Z=2,表示这条道路为城市X 和城市Y之间的双向道路。
1≤N≤100000,1≤M≤500000,
1≤X,Y≤N,1≤Z≤2,1≤商品价格≤100。 - 输出
- 输出1个整数,表示最多能赚取的旅费。如果没有进行贸易,则输出0。
- 样例输入
-
5 5 4 3 5 6 1 1 2 1 1 4 1 2 3 2 3 5 1 4 5 2
搞了大半天还是不对,先贴下来,以后再搞 TT
- 第一次没有压缩,直接用搜索写的不对,后来看了部长的代码:
View Code
/* 思路: 利用最短路的变形 分别从起点搜一次 从终点搜一次 从起点搜出从起点到达各点的最小值 从终点搜出从终点到达各点的最大值(所有可以到达的点) 主要思想是: 从 1 到 i 再从 i 到 n 从 1 到 i 时 路径是正着存的 从i 到 n 时我们把路径反着存一次 变成求 从 n 到 i 了(此处最重要) */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define qmax(a,b) ((a)>(b))?(a):(b) #define qmin(a,b) ((a)<(b))?(a):(b) using namespace std; const int roadnum=500001; const int citynum=100001; struct node { int e; int next; }edge[roadnum*2]; int k1[citynum],k2[citynum]; bool flag1[citynum],flag2[citynum]; int maxval[citynum],minval[citynum]; int n,m; int k=0; queue <int> q; void ADD(int from,int to) { edge[k].e=to; edge[k].next=k1[from]; k1[from]=k++; edge[k].e=from; edge[k].next=k2[to]; k2[to]=k++; } void init() { int i,x,y,z; memset(flag1,0,sizeof(flag1)); memset(flag2,0,sizeof(flag2)); memset(k1,-1,sizeof(k1));//从起点搜索用 memset(k2,-1,sizeof(k2));//从终点搜索用 for(i=1;i<=n;++i) { scanf("%d",&minval[i]); maxval[i]=minval[i]; } while(m--) { scanf("%d%d%d",&x,&y,&z); ADD(x,y); if(2==z)ADD(y,x); } } int spfa() { int x,y,i; while(!q.empty())q.pop(); q.push(1); flag1[1]=1; while(!q.empty())// 这个while() 控制从 从起点 可以到达的所有点可以取的最小值 { x = q.front(); q.pop(); for(i=k1[x];i!=-1;i=edge[i].next) { y= edge[i].e; minval[y]=qmin(minval[x],minval[y]); if(!flag1[y]) { q.push(y); flag1[y]=1; } } } q.push(n); flag2[n]=1; while(!q.empty())// 因为路径反着存了一次 我们从终点 逆向搜回去 可以到达各点的最大值 { //相当于从各点走到终点的最大值(因为路径反存了一次) x = q.front(); q.pop(); for(i=k2[x];i!=-1;i=edge[i].next) { y = edge[i].e; maxval[y]=qmax(maxval[x],maxval[y]); if(!flag2[y]) { q.push(y); flag2[y]=1; } } } int te=0; for(i=1;i<=n;++i) if(flag1[i] && flag2[i] && maxval[i]-minval[i]>te)// flag1[i]!=0表明从起点可以到这个点 te=maxval[i]-minval[i]; //flag2[i]!=0表明从点 i 可以到达终点 return te; } int main() { while(EOF != scanf("%d%d",&n,&m)) { init(); printf("%d\n",spfa()); } return 0; }
我还是想走我的路线,但是一直不对,郁闷,不知那里除了问题。
错误代码:
View Code#include<stdio.h> #include<string.h> #include<queue> using namespace std; struct node{ int r; int u; int next; }; int maxv[100001],minv[100001],mins[100001]; int sign[100001],value[100001]; int k[100001]; node edge[200001]; int n,m,t,num; queue<int>q; void insert(int from,int to,int z)//路径压缩 { edge[t].r=to; edge[t].u=z; edge[t].next=k[from]; k[from]=t++; } void find() { int i,f,x,y; while(!q.empty()) q.pop(); q.push(1); maxv[1]=value[1]; minv[1]=value[1]; mins[1]=value[1];//标记之前的最小数 sign[1]=1; while(!q.empty()) { x=q.front(); q.pop(); if(x==n) if(maxv[n]-minv[n]>num) num=maxv[n]-minv[n];//当搜到N就判断一次 //sign[x]=0; for(f=x,i=k[x];i!=-1;i=edge[i].next)//f是上一个相邻的数 { y=edge[i].r; if(edge[i].u==2) { if(value[y]<(minv[f]<value[f]?minv[f]:value[f])) minv[y]=value[y]; else minv[y]=minv[f]<value[f]?minv[f]:value[f]; if(value[y]>(maxv[f]>value[f]?maxv[f]:value[f])) maxv[y]=value[y]; else maxv[y]=maxv[f]>value[f]?maxv[f]:value[f]; mins[y]=minv[y]; } else { if(value[y]>maxv[f]) { maxv[y]=value[y]; minv[y]=mins[f];//当最大值改变时,最小值才改变 } else { maxv[y]=maxv[f]; minv[y]=minv[f]; } // minv[y]=minv[f]; if(value[y]<mins[f]) mins[y]=value[y]; else mins[y]=mins[f]; } if(!sign[y]) { q.push(y); if(y!=5) sign[y]=1; } // f=i; } } return; } int main() { int i,x,y,z; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;++i) { scanf("%d",&value[i]); } t=0; num=-1; memset(k,-1,sizeof(k)); memset(sign,0,sizeof(sign)); while(m--) { scanf("%d%d%d",&x,&y,&z); insert(x,y,z); } find(); printf("%d\n",num); } return 0; }