【最短路】图论复习(二)
来源:互联网 发布:淘宝差评怎么改好评 编辑:程序博客网 时间:2024/05/18 17:25
最短路问题,有Bellman-Ford,SPFA,Dijkstra,Floyd这几种算法,我最先学Bellman-Ford,但在学了SPFA和Dijkstra只好几乎没用过它了,效率比较差,图论的题最短路算做得比较多的,这里就选几道代表题来复习吧。
第一道:智捅马蜂窝
典型的最短路,首先按照题意把图建好,然后一次Dijkstra就行了,不过我习惯写priority_queue,据说在考试写有风险(NOIP的话)?知道的留个言啊,这个言论让我后面都手写堆了。近乎裸题,不多说了。
代码:
#include<cstdio>#include<cstring>#include<cmath>#include<queue>using namespace std;const int maxn = 100 + 10;const int inf = 0x7fffffff;int n;int v;double x[maxn],y[maxn];bool flag[maxn][maxn];bool done[maxn];double path[maxn][maxn],dist[maxn];void init(){ freopen("hornet.in","r",stdin); freopen("hornet.out","w",stdout);}double cal(int i,int j){ double com,com2; if(!flag[i][j]) { return inf; } com = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j])); com2 = com/v; return com2;}void create_map(){ for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) { if(i == j) { path[i][j] = 0; } else { path[i][j] = cal(i,j); } } for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) { if(x[i] == x[j] && y[i] < y[j]) { flag[j][i] = true; path[j][i] = sqrt(2*(y[j] - y[i]) / 10.00); } } }void readdata(){ memset(flag,false,sizeof(flag)); memset(done,false,sizeof(done)); memset(path,-1,sizeof(path)); scanf("%d%d",&n,&v); for(int i = 1;i <= n;i++) { int t; scanf("%lf%lf",&x[i],&y[i]); scanf("%d",&t); if(t!=0)flag[t][i] = flag[i][t] = true; } create_map();}void predoing(){ for(int i = 1;i <= n;i++) dist[i] = 1e30;}void solve(){ typedef pair<double,int>pii; priority_queue<pii,vector<pii>,greater<pii> >q; predoing(); dist[1] = 0; q.push(make_pair(dist[1],1)); while(!q.empty()) { pii u = q.top();q.pop(); if(done[u.second])continue; int k = u.second; double min = dist[k]; done[k] = true; for(int i = 1;i <= n;i++) { if(!flag[k][i])continue; if(done[i])continue; if(min + path[k][i] < dist[i]) { dist[i] = min + path[k][i]; q.push(make_pair(dist[i],i)); } } } printf("%.2lf",dist[n]); }int main(){ init(); readdata(); solve(); return 0;}
第二道:微子危机——战略
是最短路的一个变种,就是确定了起点但没确定终点的最短路,最开始做的时候还没看出来。方法就是从起点开始每到达一个点就累加ans,所有点都到达之后就求出了所求的ans了,知道了方法之后也算一道简单的题吧,不过在这道题中我手写了堆,还用了构造函数。没有用STL,所以有点冗长,凑合着看吧。
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int inf = 0x7fffffff;const int maxn = 10000 + 10;const int maxm = 500000 + 10;struct tnode{ int d,w; tnode(){}; tnode(int w,int d):w(w),d(d){};}node[maxn];struct pnode{ int dian,quan;pnode *next;pnode(){} pnode(int dian,int quan,pnode* next):dian(dian),quan(quan),next(next){}}*first[maxn],__[maxm << 1],*tot = __;tnode heap[maxm];int dist[maxn];bool done[maxn];int n,m,l;int size = 0;void init(){ freopen("tyvj1221.in","r",stdin); freopen("tyvj1221.out","w",stdout);}void readdata(){ scanf("%d%d%d",&n,&m,&l); for(int i = 1;i <= l;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); first[x] = new(tot++)pnode(y,z,first[x]); first[y] = new(tot++)pnode(x,z,first[y]); }}void del(){ heap[1] = heap[size--]; int i = 1; int j = i << 1; if(j < size && heap[j].w > heap[j+1].w)++j; while(j <= size && heap[i].w > heap[j].w) { swap(heap[i],heap[j]); i = j; j = j << 1; if(j < size && heap[j].w > heap[j+1].w)++j; }}void add(tnode x){ heap[++size] = x; int i = size; int j = i >> 1; while(i > 1 && heap[i].w < heap[j].w) { swap(heap[i],heap[j]); i = j; j = i >> 1; } }void solve(){ int ans = 0;int count = 0; for(int i = 1;i <= n;i++)dist[i] = inf; memset(done,false,sizeof(done)); dist[m] = 0; add(tnode(dist[m],m)); while(size) { tnode u = heap[1];del(); if(done[u.d])continue; int k = u.d; int min = u.w; done[k] = true; ans += min; ++count; for(pnode *p = first[k];p != NULL;p = p->next) { if(done[p->dian])continue; if(min + p->quan < dist[p->dian]) { dist[p->dian] = min + p->quan; add(tnode(dist[p->dian],p->dian)); } } } if(count == n) { printf("%d M(s) are needed.",ans); } else printf("Sth wrong.");}int main(){ init(); readdata(); solve(); return 0;}第三题:心灵的抚慰
一道最小环问题。做那么些题就遇到了这一道。思想就是在做Floyd的时候顺便把最小环求出来,也近乎裸题,不知道在不在NOIP范围,感兴趣的见:最小环
还记得当时对着这道题一筹莫展的时候,一问神牛,10分钟不到就把代码打了出来,然后A了。。。当时那个自惭形秽啊~不说了、
代码:
#include<cstdio>#include<cstring>using namespace std;const int inf=0x7f7f7f7f;const int maxn=250+10;int n,m,ans;int map[maxn][maxn];int f[maxn][maxn];void init(){ freopen("rqnoj389.in","r",stdin); freopen("rqnoj389.out","w",stdout);}void readdata(){ int a,b,c; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { map[i][j]=map[j][i]=inf >> 2; f[i][j]=f[j][i]=inf >> 2; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); map[a][b]=map[b][a]=c; f[a][b]=f[b][a]=c; } }int min(int a,int b){ return a<b?a:b;}void solve(){ ans=inf >> 2; for(int k=1;k<=n;k++) { for(int i=1;i<k;i++) for(int j=i+1;j<k;j++) { ans=min(ans,map[i][j]+f[k][i]+f[j][k]); } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) {if(k==i || k==j || i==j)continue; map[i][j]=min(map[i][j],map[i][k]+map[k][j]); } } if (ans==inf >> 2) printf("He will never come back."); else printf("%d",ans);}int main(){ init(); readdata(); solve(); return 0; }
总结:这些题肯定不能代表所有类型的题(NOIP),但是我一直抱着Dijkstra+heap走天下的思想,其他类型的题也就做得少了。其实图论的难点就在建图了,只要能抽象出模型,打代码应该是比较简单的事情了。
- 【最短路】图论复习(二)
- 图论专题(二)POJ1125最短路
- 最短路复习
- 最后复习之最短路
- NOIP复习-005——最短路
- (复习)图论--最短路--SPFA算法
- (复习)图论--最短路--Floyd算法
- (复习)图论--最短路--Dijkstra算法
- 【学/复习记录】最/次/k短路
- 图论模板-最短路
- 图论之最短路
- 图论之最短路
- (精)(图论加强)最短路问题(floyd算法)(复习一下,时间复杂度是n^3)
- (POJ 1511)Invitation Cards 有向图来回最短路 + SPFA (复习必看题)
- 图论复习1,贴几个求单源最短路的模板
- 图论算法 最短路 Floyd
- 图论专题总结—最短路
- 图论专题小结:最短路算法
- MYSQL 5.5安装
- Android 尺寸
- 内核同步机制-信号量
- UML面向对象分析与设计解析
- C#中TreeView组件使用方法初步
- 【最短路】图论复习(二)
- 随机取数据、打乱数组、打乱数据
- Fragment 学习
- poj 1815(最小割+枚举)
- 学习Joomla2--修改版权信息
- 长连接与短连接
- 11g sqlplus 乱码
- Android 9 patch 图片
- java多线程