寒假第九次训练-最短路
A - 最短路
题目大意:给n个路口,m条路,走每条路花费不等的时间,求从1号路口到n号路口的最短时间
解题思路:裸dijkstra
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <sstream>using namespace std;#define MAXN 200+10#define INF 1<<20int m,n;int d[105][105],cost[105];void dijkstra(int s){ int v=-1; bool used[105]; memset(used,0,sizeof(used)); cost[s]=0; while (true) { v=-1; for (int u=1;u<=n;u++) if (!used[u] && (v==-1 || cost[v]>cost[u])) v=u; if (v==-1) break; used[v]=true; for (int u=1;u<=n;u++) if (d[v][u]>=0) cost[u]=min(cost[u],cost[v]+d[v][u]); }}int main(){ while (scanf("%d%d",&n,&m),m+n) { memset(d,-1,sizeof(d)); fill(cost,cost+105,INF); while (m--) { int u,v,dis; scanf("%d%d%d",&u,&v,&dis); d[u][v]=dis; d[v][u]=dis; } dijkstra(1); printf("%d\n",cost[n]); } return 0;}
B - Wormholes
题目大意:给定一个图,图上带正权的边无向,带负权的边有向,从1点出发,求是否存在路径使得最终返回1点且耗费时间小于0
解题思路:用bellman-ford算法,又因为可能存在负圈,所以一旦回到1点且耗费时间小于0就退出
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <sstream>using namespace std;#define MAXN 200+10#define INF 1<<20struct edge{int from,to,cost;};edge es[10000];int m,n,w,e;int d[600];void ford(int s){ bool flag; d[s]=0; while (true) { flag=false; for (int i=0;i<e;i++) { edge temp=es[i]; if (d[temp.from]!=INF && d[temp.to]>d[temp.from]+temp.cost) {d[temp.to]=d[temp.from]+temp.cost;flag=true;} if (d[1]<0) return; } if (!flag) return; }}int main(){ int F; scanf("%d",&F); while (F--) { fill(d,d+600,INF); scanf("%d%d%d",&n,&m,&w); e=0; while (m--) { int u,v,dis; scanf("%d%d%d",&u,&v,&dis); es[e].from=u;es[e].to=v;es[e].cost=dis; e++; es[e].from=v;es[e].to=u;es[e].cost=dis; e++; } while (w--) { int u,v,dis; scanf("%d%d%d",&u,&v,&dis); es[e].from=u;es[e].to=v;es[e].cost=-dis; e++; } ford(1); printf("%s\n",d[1]<0?"YES":"NO"); } return 0;}
C - Stockbroker Grapevine
题目大意:给定n个人,每个人可以和pi个说话,说话消耗数量不等的时间,求将消息传给所有人耗费的最短时间
解题思路:用n次dijkstra算法,尝试从不同起点出发的最短时间
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <sstream>using namespace std;#define MAXN 200+10#define INF 1<<20int n;int d[105],cost[105][105];int dijkstra(int s){ bool used[105]; int v,mx=-1; memset(used,0,sizeof(used)); fill(d,d+105,INF); d[s]=0; while (true) { v=-1; for (int u=1; u<=n; u++) if (!used[u] && (v==-1 || d[v]>d[u])) v=u; if (v==-1) break; used[v]=true; for (int u=1; u<=n; u++) { if (d[u]>d[v]+cost[v][u]) { d[u]=d[v]+cost[v][u]; mx=max(mx,d[u]); //printf("%d\n",mx); } } } return mx;}int main(){ bool iszero[105]; while (scanf("%d",&n),n) { fill(iszero,iszero+105,0); for (int i=0; i<105; i++) for (int j=0; j<105; j++) cost[i][j]=INF; for (int v=1; v<=n; v++) { int num; scanf("%d",&num); if (!num) iszero[v]=true; while (num--) { int u,t; scanf("%d%d",&u,&t); cost[v][u]=t; } } pair<int,int> rec; rec.second=INF; for (int v=1; v<=n; v++) { if (iszero[v]) continue; else { int val=dijkstra(v); bool flag=true; for (int i=1;i<=n;i++) if (d[i]==INF) flag=false; if (rec.second>val && flag) rec=make_pair(v,val); } } if (rec.second==INF) printf("disjoint\n"); else printf("%d %d\n",rec.first,rec.second); } return 0;}
D - 昂贵的聘礼
题目大意:你要从酋长手中迎娶他的女儿,需要支付n金币的彩礼,这个部落所有人卖东西都有本身的价格和如果提供替代品的优惠价格,但是每个人有自身等级,如果曾经交易的人与目前交易的人等级差超过m级就无法交易,求花费最少金币数
解题思路:将所有人的等级按编号存起来,然后从最低的等级(保证可以交易到酋长)交易到最高的等级(同上),注意每次设置上限,即本次最低等级加上m。以酋长为终点,dijkstra循环尝试源点,取最小值。
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <sstream>using namespace std;#define MAXN 200+10#define INF 1<<20int n,m;int d[105],cost[105][105],rank_[105],max_rank=-1;int dijkstra(int s,int l){ bool used[105]; int v; memset(used,0,sizeof(used)); fill(d,d+105,INF); d[s]=cost[s][s]; while (true) { v=-1; for (int u=1; u<=n; u++) if (!used[u] && (v==-1 || d[v]>d[u]) && rank_[u]>=max_rank-m+l && rank_[u]<=max_rank+l) v=u; if (v==-1) break; used[v]=true; for (int u=1; u<=n; u++) { if (rank_[u]>=max_rank-m+l && rank_[u]<=max_rank+l && d[u]==INF) d[u]=cost[u][u]; if (rank_[u]>=max_rank-m+l && rank_[u]<=max_rank+l && d[u]>d[v]+cost[v][u]) { d[u]=d[v]+cost[v][u]; //printf("%d-%d:%d\n",v,u,d[u]); } } }}int main(){ for (int i=0; i<105; i++) for (int j=0; j<105; j++) cost[i][j]=INF; scanf("%d%d",&m,&n); for (int i=1; i<=n; i++) { int money,rk,num; scanf("%d%d%d",&money,&rk,&num); cost[i][i]=money; rank_[i]=rk; if (i==1) max_rank=rk; while (num--) { int no,mon; scanf("%d%d",&no,&mon); cost[no][i]=mon; } } int ans=INF; for (int l=0; l<=m; l++) { for (int i=1; i<=n; i++) { if (rank_[i]==max_rank-m+l) { dijkstra(i,l); ans=min(ans,d[1]); } } } printf("%d\n",ans); return 0;}