6.2.1 HDU2544 最短路 裸的dijkstra
6.2.2 HDU2112 HDU Today 数据规模小,map转字符串为数字点,然后dijkstra
6.2.3 HDU1385 Minimum Transport Cost
利用dijk的特性来记录路径,路径相等时比较当前路径和已存路径的字典序
#include <cstdio> #include <algorithm> #include <queue> #include <cstdlib> #include <string.h> #define MAXN 1001 #define INF 1e9 using namespace std; struct node{ int v,i; node(int a,int b){v=a,i=b;} bool operator<(const node& n)const{ return v>n.v; } }; int n,map[MAXN][MAXN],done[MAXN],d[MAXN],cost[MAXN],pre[MAXN]; void outpath(int st,int en){ if(pre[en]!=st)outpath(st,pre[en]); printf("-->%d",en); } int com(int st,int p1,int p2,int p){ int l1=2,l2=2,s1[MAXN],s2[MAXN]; s1[0]=p,s2[0]=p,s1[1]=p1,s2[1]=p2; while(p1!=st){s1[l1++]=pre[p1];p1=pre[p1];} while(p2!=st){s2[l2++]=pre[p2];p2=pre[p2];} /* 这个是对字典序错误的理解 并不是长度优先 if(l1>l2)return 0; else if(l1<l2)return 1; for(int i=l2-1;i>=0;i--){ if(s1[i]>s2[i])return 0; else if(s1[i]<s2[i])return 1; } */ l1--,l2--; while(1){ if(s1[l1]>s2[l2]) return 0; else if(s1[l1]<s2[l2]) return 1; l1--,l2--; if(l2<0) return 0; else if(l1<0) return 1; } return 0; } void dij(int st,int en){ if(st==en){ printf("From %d to %d :\n",st,en); printf("Path: %d",st); printf("\nTotal cost : 0\n\n"); return; } priority_queue<node> q; memset(done,0,sizeof done); memset(pre,-1,sizeof pre); for(int i=1;i<=n;i++)d[i]=INF; d[st]=0; q.push(node(d[st],st)); while(!q.empty()){ node nd=q.top();q.pop(); int u=nd.i; if(done[u])continue; done[u]=1; for(int i=1;i<=n;i++){ if(d[i]>=d[u]+map[u][i]+cost[i]){ if(d[i]==d[u]+map[u][i]+cost[i]&&!com(st,u,pre[i],i))continue; d[i]=d[u]+map[u][i]+cost[i]; pre[i]=u; q.push(node(d[i],i)); } } } printf("From %d to %d :\n",st,en); printf("Path: %d",st);outpath(st,en);printf("\n"); printf("Total cost : %d\n\n",d[en]-cost[en]); } int main(){ while(scanf("%d",&n),n){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&map[i][j]); if(map[i][j]==-1)map[i][j]=INF; } } for(int i=1;i<=n;i++)scanf("%d",&cost[i]); int st,en; while(scanf("%d%d",&st,&en)){ if(st==-1&&en==-1)break; dij(st,en); } } }
6.2.4 HDU2923 Einbahnstrasse
FLOYD ,注意两点之间可能会有多条路,只记录权值最小的
#include <cstdio> #include <iostream> #include <map> #include <string> #include <string.h> using namespace std; string s,s2,s3,des[1005]; map<string,int> mp; int n,c,r,ns,maps[105][105]; int main(){ int cas=1; while(cin>>n>>c>>r,n||c||r){ ns=0;mp.clear(); cin>>s; mp[s]=++ns; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)maps[i][j]=1e9; for(int i=0;i<c;i++){ cin>>des[i]; if(mp.count(des[i])==0)mp[des[i]]=++ns; } for(int i=0;i<r;i++){ cin>>s>>s2>>s3; if(mp.count(s)==0)mp[s]=++ns; if(mp.count(s3)==0)mp[s3]=++ns; int t1=mp[s],t2=mp[s3]; int ind=0,dis=0; while(s2[ind]<'0'||s2[ind]>'9')ind++; while(s2[ind]>='0'&&s2[ind]<='9')dis=dis*10+s2[ind]-'0',ind++; //可能会有多条路径,选最短的 if(s2[0]=='<'&&dis<maps[t2][t1])maps[t2][t1]=dis; if(s2[s2.length()-1]=='>'&&dis<maps[t1][t2])maps[t1][t2]=dis; } //直接FLOYD for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(maps[i][j]>maps[i][k]+maps[k][j])maps[i][j]=maps[i][k]+maps[k][j]; } } } int res=0; for(int i=0;i<c;i++) res+=maps[1][mp[des[i]]]+maps[mp[des[i]]][1]; printf("%d. %d\n",cas++,res); } }
6.2.5 HDU2722 Here We Go(relians) Again
建图真的是很麻烦啊,一共(n+1)*(m+1)个点,建图后dijkstra就行了
#include <string.h> #include <cstdio> #include <queue> #define INF 1e9 using namespace std; struct node{ int v,i; node(int a,int b){v=a,i=b;} bool operator <(const node& a)const{return v>a.v;} }; int n,m,map[500][500]; int done[500],d[500]; int dij(){ priority_queue<node> q; memset(done,0,sizeof done); for(int i=1;i<=(n+1)*(m+1);i++)d[i]=INF; d[1]=0; q.push(node(d[1],1)); while(!q.empty()){ node nd=q.top();q.pop(); int u=nd.i; if(done[u])continue; done[u]=1; for(int i=1;i<=(n+1)*(m+1);i++){ if(d[i]>d[u]+map[u][i]){ d[i]=d[u]+map[u][i]; q.push(node(d[i],i)); } } } if(d[(n+1)*(m+1)]==INF)return -1; else return d[(n+1)*(m+1)]; } int main(){ char s[3];int v; while(scanf("%d%d",&n,&m),n||m){ for(int i=1;i<=(n+1)*(m+1);i++)for(int j=1;j<=(n+1)*(m+1);j++)map[i][j]=INF; //input 建图很麻烦 一共(n+1)*(m+1)个点 int n1,n2; for(int i=1;i<=2*n+1;i++){ if(i%2==1){ for(int j=1;j<=m;j++){ n1=(i/2)*(m+1)+j,n2=n1+1; scanf("%d%s",&v,s); if(v==0)continue; if(s[0]=='*')map[n1][n2]=map[n2][n1]=2520/v; else if(s[0]=='<')map[n2][n1]=2520/v; else if(s[0]=='>')map[n1][n2]=2520/v; } }else{ for(int j=1;j<=m+1;j++){ n1=(i/2-1)*(m+1)+j,n2=n1+m+1; scanf("%d%s",&v,s); if(v==0)continue; if(s[0]=='*')map[n1][n2]=map[n2][n1]=2520/v; else if(s[0]=='v')map[n1][n2]=2520/v; else if(s[0]=='^')map[n2][n1]=2520/v; } } } /* for(int i=1;i<=(n+1)*(m+1);i++){ for(int j=1;j<=(n+1)*(m+1);j++){ printf("%d ",map[i][j]); } printf("\n"); } */ int r=dij(); if(r==-1)printf("Holiday\n"); else printf("%d blips\n",r); } return 0; }
6.2.6 HDU2377 Bus Pass
看了半天才看懂题目的意思,就是给一张图,然后给一个公交路线。然后在地图中找一个点,使这个点到所有公交路线经过的点的最大距离最小。
从公交路线上的每个点BFS整幅图,就可以得到地图上所有点到这个公交点的距离,记录每个点到公交路线点集的最大距离,即为该点到公交路线的最大值,然后在这些点里选一个值最小的就可以了。
#include <cstdio> #include <queue> #include <string.h> #define INF 1e9 using namespace std; int cas,nz,nr,mr[21]; int map[10000][11],vis[10000],res[10000],u; void bfs(int st){ memset(vis,0,sizeof vis); queue<int> q; q.push(st); vis[st]=1; while(!q.empty()){ int nu=q.front();q.pop(); for(int i=1;i<=map[nu][0];i++){ int t=map[nu][i]; if(!vis[t]){ vis[t]=vis[nu]+1; q.push(t); } } } //跟新较大值为当前点到路线点集最远点的最近距离,不能到达点跟新为无穷大 for(int i=1;i<=10000;i++){ if(!vis[i])res[i]=INF; else res[i]=max(res[i],vis[i]); } } int main(){ scanf("%d",&cas); while(cas--){ memset(map,0,sizeof map); memset(res,0,sizeof res); scanf("%d%d",&nr,&nz); for(int i=0;i<nr;i++){ scanf("%d",&u); scanf("%d",&map[u][0]); for(int j=1;j<=map[u][0];j++)scanf("%d",&map[u][j]); } //对每个汽车经过点BFS,找出其它点到它的最短路径 for(int i=1;i<=nz;i++){ scanf("%d",&mr[i]); for(int j=1;j<=mr[i];j++){ scanf("%d",&u); bfs(u); } } //找出到点集最远点距离最近的点 int r=INF,rind; for(int i=1;i<10000;i++){ if(res[i]<r){ r=res[i]; rind=i; } } printf("%d %d\n",r,rind); } return 0; }
6.2.7 HDU3191 How Many Paths Are There 求次短路条数
#include<iostream> #include<algorithm> #define N 55 #define M 10000 #define inf 0x7fffffff using namespace std; int cnt[N][2],dis[N][2]; bool h[N][2]; int NE,head[N]; int n,m; struct node{ int next,v,w; node(){}; node(int a,int b,int c){ next=a;v=b;w=c; } }E[M]; void init(){ NE=0; memset(head,-1,sizeof(head)); } void insert(int u,int v,int w){ E[NE]=node(head[u],v,w); head[u]=NE++; } void dijkstra(int beg,int end){ for(int i=0;i<=n;i++){ dis[i][0]=dis[i][1]=inf; cnt[i][0]=cnt[i][1]=0; } memset(h,0,sizeof(h)); dis[beg][0]=0; cnt[beg][0]=1; while(true){ int u,flag; int Min=inf; for(int i=0;i<n;i++){ if(!h[i][0]&&dis[i][0]<Min){ Min=dis[i][0]; u=i;flag=0; } else if(!h[i][1]&&dis[i][1]<Min){ Min=dis[i][1]; u=i;flag=1; } } if(u==end&&flag==1) break; if(Min==inf) break; h[u][flag]=1; for(int i=head[u];i!=-1;i=E[i].next){ int v=E[i].v; int w=dis[u][flag]+E[i].w; if(dis[v][0]>w){ if(dis[v][0]!=inf){ dis[v][1]=dis[v][0]; cnt[v][1]=cnt[v][0]; } dis[v][0]=w; cnt[v][0]=cnt[u][flag]; } else if(dis[v][0]==w) cnt[v][0]+=cnt[u][flag]; else if(dis[v][1]>w){ dis[v][1]=w; cnt[v][1]=cnt[u][flag]; } else if(dis[v][1]==w) cnt[v][1]+=cnt[u][flag]; } } printf("%d %d\n",dis[end][1],cnt[end][1]); } int main(void){ int s,t; while(~scanf("%d%d%d%d",&n,&m,&s,&t)){ init(); while(m--){ int x,y,w; scanf("%d%d%d",&x,&y,&w); insert(x,y,w); } dijkstra(s,t); } }
6.2.8 HDU3399 In Action DP+Dijkstra
破坏地图上的点,破坏的能量超过一半时系统被破坏
先用最短路求出到地图上每个点的最短路,即为到每个点消耗的最小花费,然后使用DP,01背包,重量为能量,权值为到每个点的花费。然后扫描一遍得到当背包被填充了一半以上时的最小花费和。
#include <cstdio> #include <string.h> #include <queue> #include <algorithm> #define MAXN 105 #define INF 1e9 using namespace std; struct node{ int v,i; node(int a,int b){v=a,i=b;} bool operator<(const node& nd)const{return v>nd.v;} }; int cas,n,m,u,v,w,tpow; int map[MAXN][MAXN],pow[MAXN],d[MAXN],done[MAXN],dd[MAXN*MAXN]; void dij(){ priority_queue<node> q; memset(done,0,sizeof done); for(int i=0;i<=n;i++)d[i]=INF; d[0]=0; q.push(node(d[0],0)); while(!q.empty()){ node nd=q.top();q.pop(); int u=nd.i; if(done[u])continue; done[u]=1; for(int i=0;i<=n;i++){ if(d[i]>d[u]+map[u][i]){ d[i]=d[u]+map[u][i]; q.push(node(d[i],i)); } } } } int dp(){ //DP求最小值 for(int i=0;i<=tpow;i++)dd[i]=INF; dd[0]=0; for(int i=1;i<=n;i++){ for(int j=tpow;j>=pow[i];j--){ dd[j]=min(dd[j],dd[j-pow[i]]+d[i]); } } //找出大于一半背包时的最小路径和 int res=INF; for(int i=tpow/2+1;i<=tpow;i++){ res=min(res,dd[i]); } if(res<INF)return res; else return -1; } int main(){ scanf("%d",&cas); while(cas--){ scanf("%d%d",&n,&m); for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)map[i][j]=INF; tpow=0; //Input for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&w); if(w<map[u][v])map[u][v]=map[v][u]=w; } for(int i=1;i<=n;i++){ scanf("%d",&pow[i]); tpow+=pow[i]; } //求到每点的最短路 dij(); /* 转化为DP问题 每个点为物品,路径为权值,能量为重量 求装满一半背包的最小权值和 */ int r=dp(); if(r==-1)printf("impossible\n"); else printf("%d\n",r); } }