scu 4444 travel
2015-10-02 17:09
357 查看
链接
这道题目很新颖,但是不会做(:зゝ∠)。看了下叉姐的代码,简单易懂。
题目大意是给你n个点,我们知道最多存在n*(n-1)/2条边,其中m条边是题目给出的,经过它们需要花费的时间为a,另外剩下的花费时间为b(为了方便,我们就叫a边和b边)问你从起点到终点(1号点到n号点),需要花费的最短时间是多少。
思路是这样的,我们先用临界表将所有的边存储下来,然后在以起点为开头的邻接表中找是否有直接到终点的a边。
1.如果没有的话,那么说明从起点到终点有一条b边。然后我们从起点开始寻找一条能间接通往终点,并且由a组成的边,如果有的话,且总距离为res,那么最后的结果就是 ans = Min(b,res).
2.如果有的话,那么说明从起点到终点有一条a边。这种情况稍微复杂些。我们用mark[i]来记录i点是否属于mark[i]的邻接表中,用set来维护一个未被访问的点。然后先将起点放入队列,弹出一个节点,我们就遍历一遍其所有的邻接点,我们用mark[i]记录,记录好以后,我们寻找比当前节点编号大的节点v,并判断它们之间是否有边(用mark[v] == u来判断,如果不等于的话,那么它们之间就是没有边),然后更新下由b组成的最短路。如果最终发现到终点是存在这么一条由b组成的路,且总距离为res,那么最后的结果就是 ans = Min(a,res)。
这道题目很新颖,但是不会做(:зゝ∠)。看了下叉姐的代码,简单易懂。
题目大意是给你n个点,我们知道最多存在n*(n-1)/2条边,其中m条边是题目给出的,经过它们需要花费的时间为a,另外剩下的花费时间为b(为了方便,我们就叫a边和b边)问你从起点到终点(1号点到n号点),需要花费的最短时间是多少。
思路是这样的,我们先用临界表将所有的边存储下来,然后在以起点为开头的邻接表中找是否有直接到终点的a边。
1.如果没有的话,那么说明从起点到终点有一条b边。然后我们从起点开始寻找一条能间接通往终点,并且由a组成的边,如果有的话,且总距离为res,那么最后的结果就是 ans = Min(b,res).
2.如果有的话,那么说明从起点到终点有一条a边。这种情况稍微复杂些。我们用mark[i]来记录i点是否属于mark[i]的邻接表中,用set来维护一个未被访问的点。然后先将起点放入队列,弹出一个节点,我们就遍历一遍其所有的邻接点,我们用mark[i]记录,记录好以后,我们寻找比当前节点编号大的节点v,并判断它们之间是否有边(用mark[v] == u来判断,如果不等于的话,那么它们之间就是没有边),然后更新下由b组成的最短路。如果最终发现到终点是存在这么一条由b组成的路,且总距离为res,那么最后的结果就是 ans = Min(a,res)。
#include<stdio.h> #include<iostream> #include<string> #include<string.h> #include<algorithm> #include<iomanip> #include<vector> #include<time.h> #include<queue> #include<stack> #include<iterator> #include<math.h> #include<stdlib.h> #include<limits.h> #include<map> #include<set> #include<bitset> //#define ONLINE_JUDGE #define eps 1e-5 #define INF 0x7fffffff #define FOR(i,a) for((i)=0;i<(a);(i)++) #define MEM(a) (memset((a),0,sizeof(a))) #define sfs(a) scanf("%s",a) #define sf(a) scanf("%d",&a) #define sfI(a) scanf("%I64d",&a) #define pf(a) printf("%d\n",a) #define pfI(a) printf("%I64d\n",a) #define pfs(a) printf("%s\n",a) #define sfd(a,b) scanf("%d%d",&a,&b) #define sft(a,b,num) scanf("%d%d%d",&a,&b,&num) #define for1(i,a,b) for(int i=(a);i<b;i++) #define for2(i,a,b) for(int i=(a);i<=b;i++) #define for3(i,a,b)for(int i=(b);i>=a;i--) #define MEM1(a) memset(a,0,sizeof(a)) #define MEM2(a) memset(a,-1,sizeof(a)) #define ll long long const double PI=acos(-1.0); template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} template<class T> inline T Min(T a,T b){return a<b?a:b;} template<class T> inline T Max(T a,T b){return a>b?a:b;} using namespace std; //#pragma comment(linker,"/STACK:1024000000,1024000000") int n,m,x; #define N 5000010 #define M 100010 #define Mod 1000000000 #define p(x,y) make_pair(x,y) const int MAX_len=550; int a,b; int main(){ #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif while(scanf("%d%d%d%d",&n,&m,&a,&b)!=EOF){ vector<int> G ; int u,v; for(int i=0;i<m;i++){ sfd(u,v); u--,v--; G[u].push_back(v); G[v].push_back(u); } for(int i=0;i<n;i++){ //将i点的领边排序,然后去重 sort(G[i].begin(),G[i].end()); G[i].erase(unique(G[i].begin(),G[i].end()),G[i].end()); } if(find(G[0].begin(),G[0].end(),n-1) == G[0].end()){ //从起始点到终点没有一条长度为a的边(即有一条b的边) int dis[M]; memset(dis,-1,sizeof dis); dis[0] = 0; queue<int> q; q.push(0); while(!q.empty()){ int u = q.front(); q.pop(); for(int i=0;i<(int)G[u].size();i++){ //计算从起点到终点最短路(因为dis[v]只在dis[v]==-1的时候 //更新一次,bfs又是层次遍历,所以刚开始遍历到终点那肯定是最短路) int v = G[u][i]; if(dis[v] == -1){ dis[v] = dis[u]+1; q.push(v); } } } ll ans = (ll)b; //从起点到终点有一条长度为b的边 if(dis[n-1] != -1){ //如果dis[n-1]!=-1,说明从起点到终点有一条由a长度铺设的路径 ans = Min(ans,(ll)dis[n-1]*a); } printf("%lld\n",ans); }else{ //从起点到终点有一条长度为a的边 int dis[M]; memset(dis,-1,sizeof dis); dis[0]=0; int mark[M]; //记录每个点的头结点 memset(mark,-1,sizeof mark); set<int> s; for(int i=1;i<n;i++) //维护未访问的点 s.insert(i); queue<int>q; q.push(0); while(!q.empty()){ int u = q.front(); q.pop(); for(int i=0;i<(int)G[u].size();i++){ //记录所有u节点的邻接节点 mark[G[u][i]] = u; } int p = -1; //当前节点 while(1){ set<int>::iterator it = s.upper_bound(p); //找一个比当前节点大而且未访问过的点 if(it == s.end()) break; p = *(it); if(mark[p] != u){ //如果mark[p]!=u,说明它们之间有一条为b的边 s.erase(it); dis[p] = dis[u]+1; q.push(p); } } } ll ans = (ll)a; //原本是存在一条为a的道路 if(dis[n-1] != -1){ //说明从起点到终点有一条由b铺设而成的到道路 ans = Min(ans,(ll)dis[n-1]*b); } printf("%lld\n",ans); } } return 0; }
相关文章推荐
- Java堆和栈的区别 经典总结(转载)
- Xcode 和 Mac 的一些快捷键
- swift的类和对象
- android studio 用WiFi 真机 调试 测试
- UVA - 1584 Circular Sequence
- LinkedHashMap与LRUCache实现
- Java初学者都必须理解的七大问题
- OFFICE 2007 SP3后续补丁微软官方下载地址
- pat1009Product of Polynomials (25)
- Copying files from ASM to file system
- c语言的指针
- sae url rewrite(伪静态、重定向)详解
- c++计算学分绩点代码
- 浏览器缓存浅析(二)
- AOJ 2447 A Two Floors Dungeon (状压bfs)
- ubuntu从图形用户界面切换到命令提示符界面
- 10-排序6 Sort with Swap(0, i)
- 如何在Java中使用双重检查锁实现单例
- 消息推送(一)Comet介绍
- LinkedList的实现原理分析