@Metralix
2018-03-08T22:25:23.000000Z
字数 7205
阅读 850
最短路
题目大意
某个人要从起点到终点, 有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 1005
int cost[MAXN][MAXN];
int dis[MAXN];
int sum[MAXN];
#define INF 0x3f3f3f3f
#define typec int
int 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;
}