@Metralix
2018-03-08T14:25:23.000000Z
字数 7205
阅读 1004
最短路
题目大意
某个人要从起点到终点, 有m个经济站和k个商业站, 只能乘坐一次商业站, 求最短时间。
解题思路
因为多了商业站, 所以不能直接套用最短路, 但是注意到只有一次乘坐商业站的机会, 所以直接枚举坐哪个商业站就行了, 这样,其他部分就是最短路了, 假设商业站是从a到b,花费c,那么答案就是d1[a] + d2[b] + c, d1是从起点的最短路,d2是从终点出发的最短路。
#include<map>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<cctype>#include<string>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int maxv = 500 + 5;const int max_dis = 999999999;struct Edge{int to;int dis;Edge(int to,int dis){this -> to = to;this -> dis = dis;}};int N,S,E,M,K;int X,Y,Z,cases=0;vector<Edge>G[maxv];int Sdis[maxv],Edis[maxv];int Shead[maxv],Ehead[maxv];int path[maxv],ans,Start,End,cnt;typedef pair<int,int>P;void init(){Start=-1; cnt=0;for(int i=0;i<maxv;i++) G[i].clear();memset(Shead,-1,sizeof(Shead));memset(Ehead,-1,sizeof(Ehead));fill(Sdis+1,Sdis+1+N,max_dis);fill(Edis+1,Edis+1+N,max_dis);}void dijkstra(int dis[],int head[],int s){priority_queue<P,vector<P>,greater<P> >q;while(!q.empty()) q.pop();dis[s]=0;q.push(P(0,s));while(!q.empty()){P p=q.top(); q.pop();int v=p.second;if(p.first>dis[v]) continue;for(int i=0;i<G[v].size();i++){Edge& e=G[v][i];if(dis[v]+e.dis<dis[e.to]){head[e.to]=v;dis[e.to]=dis[v]+e.dis;q.push(P(dis[e.to],e.to));}}}}void doit(){dijkstra(Sdis,Shead,S);dijkstra(Edis,Ehead,E);ans=Sdis[E];}int main(){while(scanf("%d%d%d",&N,&S,&E)!=EOF){init();scanf("%d",&M);for(int i=0;i<M;i++){scanf("%d%d%d",&X,&Y,&Z);G[X].push_back(Edge(Y,Z));G[Y].push_back(Edge(X,Z));}doit();scanf("%d",&K);for(int i=0;i<K;i++){scanf("%d%d%d",&X,&Y,&Z);if(Sdis[X]+Edis[Y]+Z<ans){Start=X; End=Y;ans=Sdis[X]+Edis[Y]+Z;}if(Sdis[Y]+Edis[X]+Z<ans){Start=Y; End=X;ans=Sdis[Y]+Edis[X]+Z;}}if(cases) printf("\n");cases++;if(Start==-1){for(int i=E;i!=-1;i=Shead[i]) path[cnt++]=i;for(int i=cnt-1;i>=0;i--){if(i==0) printf("%d\n",path[i]);else printf("%d ",path[i]);}printf("Ticket Not Used\n%d\n",ans);}else{for(int i=Start;i!=-1;i=Shead[i]) path[cnt++]=i;reverse(path,path+cnt);for(int i=End;i!=-1;i=Ehead[i]) path[cnt++]=i;for(int i=0;i<cnt;i++){if(i==cnt-1) printf("%d\n",path[i]);else printf("%d ",path[i]);}printf("%d\n%d\n",Start,ans);}}return 0;}
标签: dijkstra
题目大意
只走(A,B):存在一条从B出发回家的路,比所有从A出发回家的路径都短。问这样的路径有几条。
解题思路
先反向求一遍最短路,得到d数组。当d[B] < d[A]时,满足(A,B)路径,这样就能容易找到(A,B)路径,DFS找一遍总路径数就好了。
#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define MAXN 1005int cost[MAXN][MAXN];int dis[MAXN];int sum[MAXN];#define INF 0x3f3f3f3f#define typec intint path[MAXN],vis[MAXN];void Dijkstra(typec cost[][MAXN],typec lowcost[MAXN],int n,int beg){int i,j;typec minc;memset(vis,0,sizeof(vis));vis[beg]=1;for(i=1;i<=n;i++){lowcost[i]=cost[beg][i];path[i]=beg;}lowcost[beg]=0;path[beg]=-1;//树根的标记int pre;for(int num=2;num<n;num++){minc=INF;for(j=1;j<=n;j++)if(vis[j]==0&&lowcost[j]<minc){pre=j;minc=lowcost[j];}if(minc>=INF)break;vis[pre]=1;for(j=1;j<=n;j++)if(vis[j]==0&&lowcost[pre]+cost[pre][j]<lowcost[j]){lowcost[j]=lowcost[pre]+cost[pre][j];path[j]=pre;}}}int dfs(int i,int n){if(i==2) return 1;if(sum[i]!=-1) return sum[i];int cnt=0;for(int j=1;j<=n;j++){if(cost[i][j]<INF&&dis[j]<dis[i])cnt+=dfs(j,n);}sum[i]=cnt;return sum[i];}int main(){int i,j;int n,m;int a,b,d;while(scanf("%d",&n),n){scanf("%d",&m);for(i=1;i<=n;i++)for(j=1;j<=n;j++){if(i==j)cost[i][j]=0;else cost[i][j]=INF;}while(m--){scanf("%d%d%d",&a,&b,&d);cost[a][b]=d;cost[b][a]=d;}Dijkstra(cost,dis,n,2);memset(sum,-1,sizeof(sum));printf("%d\n",dfs(1,n));}}
标签: 最短路
题目大意
给出一个n节点m条边的无向图,每条边上有一个正权,令c等于每对结点的最短路径之和,要求删除一条边后使得新的c值最大,不连通的两个点距离视为L
解题思路
每次求单源最短路的同时记录下删除边的值,然后计算最小值就是了
#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<algorithm>#define FOR(a,b,c) for(int a=(b);a<=(c);a++)using namespace std;const int maxn = 100+10,maxm=1000+10;const int INF=1e9;struct Edge{int u,v,w,next;};int n,m,L;struct SPFA{int n;Edge e[2*maxm];int en,front[maxn];int inq[maxn],d[maxn];int p[maxn];queue<int> q;void init(int n){this->n=n;en=-1;memset(front,-1,sizeof(front));}void AddEdge(int u,int v,int w) {en++; e[en].u=u; e[en].v=v; e[en].w=w; e[en].next=front[u]; front[u]=en;}void solve(int s) {memset(inq,0,sizeof(inq));memset(p,0,sizeof(p));for(int i=1;i<=n;i++) d[i]=INF;d[s]=0; inq[s]=1; q.push(s);while(!q.empty()) {int u=q.front(); q.pop(); inq[u]=0;for(int i=front[u];i>=0;i=e[i].next) {int v=e[i].v,w=e[i].w;if(w>0 && d[v]>d[u]+w) {d[v]=d[u]+w;p[v]=i;if(!inq[v]) {inq[v]=1;q.push(v);}}}}}}spfa;vector<int> gr[maxn][maxn];int idx[maxn][maxn];int used[maxn][maxn][maxn];int sum_single[maxn];int CALC_C() {int ans=0;memset(used,0,sizeof(used));FOR(scr,1,n){spfa.solve(scr);sum_single[scr]=0;FOR(v,1,n){if(v!=scr) {int u=spfa.e[spfa.p[v]].u;used[scr][u][v]=used[scr][v][u]=1;}sum_single[scr] += spfa.d[v]==INF? L : spfa.d[v];}ans += sum_single[scr];}return ans;}int CALC_C2(int a,int b) {int ans=0;FOR(scr,1,n){if(!used[scr][a][b]) ans+=sum_single[scr];else{spfa.solve(scr);FOR(v,1,n) ans += spfa.d[v]==INF?L: spfa.d[v];}}return ans;}int main(){while(scanf("%d%d%d",&n,&m,&L)==3){int u,v,w;spfa.init(n);FOR(i,1,n) FOR(j,1,n) gr[i][j].clear();while(m--) {scanf("%d%d%d",&u,&v,&w);gr[u][v].push_back(w);gr[v][u].push_back(w);}FOR(i,1,n) FOR(j,i+1,n) if(!gr[i][j].empty()){sort(gr[i][j].begin(),gr[i][j].end());spfa.AddEdge(i,j,gr[i][j][0]);idx[i][j]=spfa.en;spfa.AddEdge(j,i,gr[i][j][0]);idx[j][i]=spfa.en;}int c=CALC_C(),c2=-1;FOR(i,1,n) FOR(j,i+1,n) if(!gr[i][j].empty()){int& e1=spfa.e[idx[i][j]].w;int& e2=spfa.e[idx[j][i]].w;if(gr[i][j].size()==1) e1=e2=-1;else e1=e2=gr[i][j][1];c2=max(c2,CALC_C2(i,j));e1=e2=gr[i][j][0];}printf("%d %d\n",c,c2);}return 0;}
标签: dijstra
题目大意
给定一个无向图,大写字母是城市,小写字母是村庄,经过城市交过路费为当前货物的%5,路过村庄固定交1,给定起点终点和到目标地点要剩下的货物,问最少要带多少货物上路,并输出路径,如果有多种方案,要求字典序最小
解题思路
dijstra的逆向运用,d数组含义变成到该结点至少需要这么多货物,然后反向建图,从终点向起点反向做一遍
#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 55;const int inf = 0x3f3f3f3f;int IDX(char ch) { if (ch >= 'A' && ch <= 'Z') return ch - 'A'; else return 26 + ch - 'a'; }char RIDX(int x) { if (x < 26) return 'A' + x; else return 'a' + x - 26; }int N = 52, M, S, E, L, V[maxn];ll D[maxn];vector<int> G[maxn], ans;struct State {int u;ll d;State (int u = 0, ll d = 0): u(u), d(d) {}bool operator < (const State& u) const { return d > u.d; }};void init () {for (int i = 0; i <= N; i++) G[i].clear();char s[5], e[5];for (int i = 0; i < M; i++) {scanf("%s%s", s, e);int u = IDX(s[0]), v = IDX(e[0]);G[u].push_back(v);G[v].push_back(u);}scanf("%d%s%s", &L, s, e);S = IDX(s[0]), E = IDX(e[0]);}ll limit (int x, ll w) {if (x >= 26) return w+1;ll l = 0, r = inf;while (l < r) {ll mid = (l + r) >> 1;ll t = mid + w;if (t - (t + 19) / 20 >= w) r = mid;else l = mid + 1;}return w + l;}ll consume(int u, ll d) {if (u >= 26) return 1;else return (d + 19) / 20;}void put (int u) {ans.push_back(u);if (u == E) return;int rec = -1;for (int i = 0; i < G[u].size(); i++) {int v = G[u][i];if (D[u] - consume(v, D[u]) == D[v] && (rec == -1 || rec > v))rec = v;}put(rec);}void dijkstra () {memset(V, 0, sizeof(V));memset(D, inf, sizeof(D));D[E] = L;priority_queue<State> Q;Q.push(State(E, D[E]));while (!Q.empty()) {int u = Q.top().u;Q.pop();if (V[u]) continue;V[u] = 1;ll w = limit(u, D[u]);for (int i = 0; i < G[u].size(); i++) {int v = G[u][i];if (D[v] > w) {D[v] = w;Q.push(State(v, w));}}}printf("%lld\n", D[S]);ans.clear();put(S);for (int i = 0; i < ans.size(); i++) {printf("%c%c", RIDX(ans[i]), i == ans.size()-1 ? '\n' : '-');}}int main () {int cas = 1;while (scanf("%d", &M) == 1 && M != -1) {init ();printf("Case %d:\n", cas++);dijkstra();}return 0;}