[kuangbin带你飞]专题四 最短路练习
Til the Cows Come HomePOJ - 2387
题意:给你一幅地图,点1~N,双向正权路,问你N到1的最短路径?
算法:Dijkstra或者SPFA
思路:因为是正权路径,可以用Dijkstra算法;SPFA区别就是可以判断负权环。
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1000+10; 14 15 struct qnode{ 16 int v,c; 17 qnode(int _v=0,int _c=0):v(_v),c(_c) {} 18 bool operator < (const qnode &r)const{ 19 return c>r.c; 20 } 21 }; 22 struct Edge{ 23 int v,cost; 24 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 25 }; 26 vector<Edge>E[MAXN]; 27 void addedge(int u,int v,int w){E[u].push_back(Edge(v,w));} 28 bool vis[MAXN]; 29 int dist[MAXN]; 30 void Dijkstra(int n,int start){ 31 memset(vis,false,sizeof vis); 32 for(int i=1;i<=n;i++) dist[i]=INF; 33 priority_queue<qnode> q; 34 dist[start]=0; 35 q.push(qnode(start,0)); 36 while(!q.empty()){ 37 qnode tmp = q.top();q.pop(); 38 int u = tmp.v; 39 if(vis[u]) continue; 40 vis[u]=true; 41 for(int i=0;i<E[u].size();i++){ 42 int v = E[u][i].v , cost = E[u][i].cost; 43 if(!vis[v]&&dist[v]>dist[u]+cost){ 44 dist[v] = dist[u] + cost; 45 q.push(qnode(v,dist[v])); 46 } 47 } 48 } 49 } 50 int main() 51 { 52 int T,N; 53 cin>>T>>N; 54 while(T--){ 55 int a,b,c;cin>>a>>b>>c; 56 addedge(a,b,c) , addedge(b,a,c); 57 } 58 Dijkstra(N,1); 59 cout<<dist[N]<<endl; 60 return 0; 61 }
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1000+10; 14 15 struct Edge{ 16 int v,cost; 17 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 18 }; 19 vector<Edge> E[MAXN]; 20 void addedge(int u,int v,int w){E[u].push_back(Edge(v,w));} 21 bool vis[MAXN]; 22 int cnt[MAXN],dis[MAXN]; 23 bool SPFA(int start,int n){ 24 memset(vis,false,sizeof vis); 25 for(int i=1;i<=n;i++) dis[i] = INF; 26 vis[start]=true,dis[start]=0; 27 queue<int> q;q.push(start); 28 memset(cnt,0,sizeof cnt);cnt[start] = 1; 29 while(q.size()){ 30 int u = q.front();q.pop(); 31 vis[u]=false; 32 for(int i=0;i<E[u].size();i++){ 33 int v = E[u][i].v; 34 if(dis[v]>dis[u]+E[u][i].cost){ 35 dis[v]=dis[u]+E[u][i].cost; 36 if(!vis[v]){ 37 vis[v] = true; 38 q.push(v); 39 if(++cnt[v]>n) return false; 40 } 41 } 42 } 43 } 44 return true; 45 } 46 int main() 47 { 48 int T,N; 49 cin>>T>>N; 50 while(T--){ 51 int a,b,c;cin>>a>>b>>c; 52 addedge(a,b,c) , addedge(b,a,c); 53 } 54 SPFA(1,N); 55 cout<<dis[N]<<endl; 56 return 0; 57 }
FroggerPOJ - 2253
题意:青蛙想要从石头1跳到石头2;其他石头是编号3~n;起点为石头1,终点石头2;问你们从起点到终点,跳到最大距离的最小可能是多少?
算法:SPFA
思路:这里只要改变路径改变方式就行了,dist[i]变成从起点到该点i途中,最大跳跃距离;
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 #include <iomanip> 10 11 using namespace std; 12 13 const int INF = 0x3f3f3f3f; 14 const int MAXN = 200+10; 15 16 struct node{ 17 int x,y; 18 node(int a,int b):x(a),y(b) {} 19 node() {} 20 int d(int a,int b){ 21 a = a - x , b = b - y; 22 return a*a + b*b; 23 } 24 }po[MAXN]; 25 bool vis[MAXN]; 26 int dis[MAXN]; 27 bool SPFA(int start,int n){ 28 memset(vis,false,sizeof vis); 29 for(int i=1;i<=n;i++) dis[i] = INF; 30 vis[start]=true,dis[start]=0; 31 queue<int> q;q.push(start); 32 while(q.size()){ 33 int u = q.front();q.pop(); 34 vis[u]=false; 35 for(int i=1;i<=n;i++){ 36 if(i==u) continue; 37 int d = max( dis[u] , po[u].d(po[i].x , po[i].y)); 38 if(dis[i]>d){ 39 dis[i]=d; 40 if(!vis[i]){ 41 vis[i] = true; 42 q.push(i); 43 } 44 } 45 } 46 } 47 return true; 48 } 49 int main() 50 { 51 int n,cas=1; 52 while(cin>>n&&n){ 53 cout<<"Scenario #"<<cas++<<endl; 54 cout<<"Frog Distance = "; 55 for(int i=1;i<=n;i++) cin>>po[i].x>>po[i].y; 56 SPFA(1,n); 57 double r = dis[2]; 58 cout<<fixed<<setprecision(3)<<sqrt(r)<<endl; 59 cout<<endl; 60 } 61 return 0; 62 }
Heavy Transportation POJ - 1797
题意:一个地图,双向路径,权值为路径的最大承重量,顾客问你从地点1到地点n,允许最大承重重量为多少?
算法:SPFA或者最小生成树
思路:这题和上一题很像,但是这里求最大,所以反过来就行了;思路2:就是将所有的路径从大到小排序,然后一个个路径进行路径联通,如果有路径相连的,就通过最小生成树,归为一棵树,如果整个地图都变成一棵树,那么最后的路径为最小路径即最大允许承重;
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1000+10; 14 15 struct Edge{ 16 int v,cost; 17 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 18 }; 19 vector<Edge> E[MAXN]; 20 void addedge(int u,int v,int w){E[u].push_back(Edge(v,w));} 21 bool vis[MAXN]; 22 int cnt[MAXN],dis[MAXN]; 23 bool SPFA(int start,int n){ 24 memset(vis,false,sizeof vis); 25 for(int i=1;i<=n;i++) dis[i] = 0; 26 vis[start]=true,dis[start]=INF; 27 queue<int> q;q.push(start); 28 memset(cnt,0,sizeof cnt);cnt[start] = 1; 29 while(q.size()){ 30 int u = q.front();q.pop(); 31 vis[u]=false; 32 for(int i=0;i<E[u].size();i++){ 33 int v = E[u][i].v; 34 int d = min(dis[u], E[u][i].cost); 35 if(dis[v]<d){ 36 dis[v]=d; 37 if(!vis[v]){ 38 vis[v] = true; 39 q.push(v); 40 if(++cnt[v]>n) return false; 41 } 42 } 43 } 44 } 45 return true; 46 } 47 int main() 48 { 49 int _,cas=1;cin>>_; 50 while(_--){ 51 int n,m; 52 cin>>n>>m; 53 for(int i=1;i<=n;i++) E[i].clear(); 54 while(m--){ 55 int a,b,c;cin>>a>>b>>c; 56 addedge(a,b,c) , addedge(b,a,c); 57 } 58 SPFA(1,n); 59 cout<<"Scenario #"<<cas++<<":"<<endl; 60 cout<<dis[n]<<endl; 61 cout<<endl; 62 } 63 return 0; 64 }
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1000+10; 14 15 struct Edge{ 16 int u,v,cost; 17 Edge(int a,int b,int c):u(a),v(b),cost(c){} 18 bool operator <(const Edge &a)const { 19 return cost > a.cost; 20 } 21 }; 22 vector<Edge>E; 23 int fa[MAXN]; 24 int FFa(int x){ 25 if(fa[x]==x) return x; 26 return fa[x]=FFa(fa[x]); 27 } 28 bool check(int n){ 29 if(FFa(1)==FFa(n)) return true; 30 return false; 31 } 32 int solve(int n){ 33 for(int i=1;i<=n;i++) fa[i] = i; 34 for(int i=0;i<E.size();i++){ 35 int u = E[i].u , v = E[i].v , w = E[i].cost; 36 int uFa = FFa(u) , vFa = FFa(v); 37 if(uFa==vFa) continue; 38 fa[vFa] = uFa; 39 if(check(n)) return w; 40 } 41 } 42 int main() 43 { 44 int _,cas=1;cin>>_; 45 while(_--){ 46 E.clear(); 47 int n,m; 48 cin>>n>>m; 49 while(m--){ 50 int a,b,c;cin>>a>>b>>c; 51 E.push_back(Edge(a,b,c)); 52 } 53 sort(E.begin(),E.end()); 54 cout<<"Scenario #"<<cas++<<":"<<endl; 55 cout<<solve(n)<<endl; 56 cout<<endl; 57 } 58 return 0; 59 }
Silver Cow Party POJ - 3268
题意:有n个农村(编号从1开始),每个农村只有一头牛,农村之间是单向正权路径,party举办农村题目给出,每头牛都需要从自己农村出发到派对,然后从派对回到自己农村,问这n头牛中的最大最短路径。
算法:SPFA
思路:做最短路径,想要看点,编号是多少到多少;第二看路,是单向还是双向?正权?非负权?有负权?(负权就存在负环);第三就是问题;这题很简单,分两段,从所属地到派对地(这里反过来求,路径也反过来存)、从派对地到所属地;然后所有牛的最短路径,来回加起来找最大就行了。
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1000+10; 14 15 struct Edge{ 16 int v,cost; 17 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 18 }; 19 vector<Edge> E1[MAXN],E2[MAXN]; 20 void addedge1(int u,int v,int w){E1[u].push_back(Edge(v,w));} 21 void addedge2(int u,int v,int w){E2[u].push_back(Edge(v,w));} 22 bool vis[MAXN]; 23 int cnt[MAXN],dis1[MAXN],dis2[MAXN]; 24 bool SPFA(int start,int n,vector<Edge> E[MAXN],int (&dis)[MAXN]){ 25 memset(vis,false,sizeof vis); 26 for(int i=1;i<=n;i++) dis[i] = INF; 27 vis[start]=true,dis[start]=0; 28 queue<int> q;q.push(start); 29 memset(cnt,0,sizeof cnt);cnt[start] = 1; 30 while(q.size()){ 31 int u = q.front();q.pop(); 32 vis[u]=false; 33 for(int i=0;i<E[u].size();i++){ 34 int v = E[u][i].v; 35 if(dis[v]>dis[u]+E[u][i].cost){ 36 dis[v]=dis[u]+E[u][i].cost; 37 if(!vis[v]){ 38 vis[v] = true; 39 q.push(v); 40 if(++cnt[v]>n) return false; 41 } 42 } 43 } 44 } 45 return true; 46 } 47 int main() 48 { 49 int n,m,x;cin>>n>>m>>x; 50 while(m--){ 51 int a,b,c;cin>>a>>b>>c; 52 addedge1(a,b,c);addedge2(b,a,c); 53 } 54 int ans = 0; 55 SPFA(x,n,E1,dis1); 56 SPFA(x,n,E2,dis2); 57 for(int i=1;i<=n;i++) ans = max(ans,dis1[i]+dis2[i]); 58 cout<<ans<<endl; 59 return 0; 60 }
Currency Exchange POJ - 1860
题意:货币交易AtoB,交易汇率RAB,手续费CAB;( A - CAB ) * RAB = B;现在你有某种货币某量(货币种类从1~N),给一些货币之间的兑换方式;问你是否存在通过兑换货币的方式,使得你原来的某种货币变多;
算法:SPFA
思路:这里货币兑换,我通过案例,数学公式模拟,只要兑换数量超过阈值就不会亏,稳赚;这里按照题目,模拟全额向外兑换扩散,dist数组:全额兑换到这种货币最大数量;这里只要兑换会初始货币就YES了
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1000+10; 14 15 struct Edge{ 16 int v; 17 double rate,cost; 18 Edge(int _v=0,double _rate=0,double _cost=0):v(_v),rate(_rate),cost(_cost) {} 19 }; 20 vector<Edge> E[MAXN]; 21 void addedge(int u,int v,double r,double w){E[u].push_back(Edge(v,r,w));} 22 bool vis[MAXN]; 23 double dis[MAXN]; 24 bool SPFA(int n,int start,double vv){ 25 memset(vis,false,sizeof vis); 26 for(int i=1;i<=n;i++) dis[i] = 0; 27 vis[start]=true,dis[start]=vv; 28 queue<int> q;q.push(start); 29 while(q.size()){ 30 int u = q.front();q.pop(); 31 vis[u]=false; 32 for(int i=0;i<E[u].size();i++){ 33 int v = E[u][i].v; 34 double d = (dis[u] - E[u][i].cost)*E[u][i].rate; 35 if(dis[v]<d){ 36 dis[v]=d; 37 if(v==start) return true; 38 if(!vis[v]){ 39 vis[v] = true; 40 q.push(v); 41 } 42 } 43 } 44 } 45 return false; 46 } 47 int main() 48 { 49 int n,m; 50 double s,v; 51 cin>>n>>m>>s>>v; 52 while(m--){ 53 int a,b; 54 double c,d,e,f; 55 cin>>a>>b>>c>>d>>e>>f; 56 addedge(a,b,c,d);addedge(b,a,e,f); 57 } 58 if(SPFA(n,s,v)) puts("YES"); 59 else puts("NO"); 60 return 0; 61 }
Wormholes POJ - 3259
题意:起点:1 ,N个点;双向正权路径;虫洞为单向负权路径,权值为时间;问能否将时间倒退1000s(多少秒不重要,有负环就可行)。
算法:SPFA
思路:这里因为有负权,需要判断负环;这题和上一题很像,dis数组:维护到达这点的最小时间;只要从起点开始回到起点就YES,或者存在负环也YES;
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 500+10; 14 15 struct Edge{ 16 int v,cost; 17 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 18 }; 19 vector<Edge> E[MAXN]; 20 void addedge(int u,int v,int w){E[u].push_back(Edge(v,w));} 21 bool vis[MAXN]; 22 int cnt[MAXN],dis[MAXN]; 23 bool SPFA(int start,int n){ 24 memset(vis,false,sizeof vis); 25 for(int i=1;i<=n;i++) dis[i] = INF; 26 vis[start]=true,dis[start]=0; 27 queue<int> q;q.push(start); 28 memset(cnt,0,sizeof cnt);cnt[start] = 1; 29 while(q.size()){ 30 int u = q.front();q.pop(); 31 vis[u]=false; 32 for(int i=0;i<E[u].size();i++){ 33 int v = E[u][i].v; 34 if(dis[v]>dis[u]+E[u][i].cost){ 35 dis[v]=dis[u]+E[u][i].cost; 36 if(v==start) return true; 37 if(!vis[v]){ 38 vis[v] = true; 39 q.push(v); 40 if(++cnt[v]>n) return true; 41 } 42 } 43 } 44 } 45 return false; 46 } 47 int main() 48 { 49 int _;cin>>_; 50 while(_--){ 51 int n,m,w;cin>>n>>m>>w; 52 for(int i=1;i<=n;i++) E[i].clear(); 53 while(m--){ 54 int a,b,c;cin>>a>>b>>c; 55 addedge(a,b,c);addedge(b,a,c); 56 } 57 while(w--){ 58 int a,b,c;cin>>a>>b>>c; 59 addedge(a,b,-c); 60 } 61 if(SPFA(1,n)) puts("YES"); 62 else puts("NO"); 63 } 64 return 0; 65 }
MPI Maelstrom POJ - 1502
题意:n台计算机;每台计算机都可以互相通信;用一个矩阵表示通信成本,自身通信成本为0,计算机a到计算机b的成本和计算机b到计算机a的成本一样,所以输入只给了必要的矩阵出来;这里注意输入就行了;从计算机1开始向外通信扩展,问到所有计算机都收到信息的最小时间成本;
算法:SPFA
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 100+10; 14 15 struct Edge{ 16 int v,cost; 17 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 18 }; 19 vector<Edge> E[MAXN]; 20 void addedge(int u,int v,int w){E[u].push_back(Edge(v,w));} 21 bool vis[MAXN]; 22 int cnt[MAXN],dis[MAXN]; 23 bool SPFA(int start,int n){ 24 memset(vis,false,sizeof vis); 25 for(int i=1;i<=n;i++) dis[i] = INF; 26 vis[start]=true,dis[start]=0; 27 queue<int> q;q.push(start); 28 memset(cnt,0,sizeof cnt);cnt[start] = 1; 29 while(q.size()){ 30 int u = q.front();q.pop(); 31 vis[u]=false; 32 for(int i=0;i<E[u].size();i++){ 33 int v = E[u][i].v; 34 if(dis[v]>dis[u]+E[u][i].cost){ 35 dis[v]=dis[u]+E[u][i].cost; 36 if(v==start) return true; 37 if(!vis[v]){ 38 vis[v] = true; 39 q.push(v); 40 if(++cnt[v]>n) return true; 41 } 42 } 43 } 44 } 45 return false; 46 } 47 int main() 48 { 49 int n; 50 while(cin>>n&&n){ 51 for(int i=1;i<=n;i++) 52 for(int j=1;j<i;j++){ 53 char ch = getchar();while(ch==' '||ch=='\n') ch=getchar(); 54 if(ch=='x') continue; 55 int a=0; 56 do{ 57 a*=10;a+=ch-'0'; 58 ch=getchar(); 59 }while(ch<='9'&&ch>='0'); 60 //cout<<a<<endl; 61 addedge(i,j,a);addedge(j,i,a); 62 } 63 SPFA(1,n); 64 int ans = 0;for(int i=1;i<=n;i++) ans = max(ans,dis[i]); 65 cout<<ans<<endl; 66 } 67 return 0; 68 }
Cow ContestPOJ - 3660
题意:n头牛有m个上下关系,单向的;根据这个关系排序,能确定排序位置的牛有多少个?
算法:Bellman_ford
思路:一开始是把所有路径记录,然后求一个公共前缀的,但是想想好像不对,因为如果已经确定前面和后面明确有多少个,那它也是确定排序位置的,相当于快排每一步,确定一个数位置一样;关键点:如果一个数确定位置了,那么确定它前面的点和后面的点总共等于n-1;这里用B_F算法求两两点最短距离,这题比较特殊,因为他们的边就是一种单向关系,dis[i][j] 和 dis[j][i]不可能同时存在,并且dis向后推的距离只会越来越大,不可能连接的就永远INF;如果dis数组不是INF,就表示两点之间是联通的,那么这两个点之间的关系是确定的;
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 100+10; 14 15 int n,m,dis[MAXN][MAXN]; 16 17 void bellman_ford(){ 18 for(int k=1;k<=n;k++) 19 for(int i=1;i<=n;i++) 20 for(int j=1;j<=n;j++) 21 if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j] = dis[i][k] + dis[k][j]; 22 } 23 24 int main() 25 { 26 cin>>n>>m; 27 memset(dis,INF,sizeof dis); 28 while(m--){ 29 int a,b;cin>>a>>b; 30 dis[a][b] = 1; 31 } 32 bellman_ford(); 33 int res[MAXN] = {0}; 34 for(int i=1;i<=n;i++) 35 for(int j=1;j<i;j++) if(dis[i][j]!=INF||dis[j][i]!=INF) res[i]++,res[j]++; 36 int ans = 0; 37 for(int i=1;i<=n;i++) if(res[i]==n-1) ans++; 38 cout<<ans<<endl; 39 return 0; 40 }
Arbitrage POJ - 2240
题意:给你货币种类和货币汇率,问你是否存在通过货币兑换获利的方法?
算法:SPFA
思路:和前面一道题差不多,起点从1到n,依次进入SPFA,如果能回到起点就能获利;
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 #include <sstream> 10 #include <stdlib.h> 11 12 using namespace std; 13 14 const int INF = 0x3f3f3f3f; 15 const int MAXN = 30+10; 16 17 map<string,int> mp; 18 19 struct Edge{ 20 int v; 21 double cost; 22 Edge(int _v=0,double _cost=0):v(_v),cost(_cost) {} 23 }; 24 vector<Edge> E[MAXN]; 25 void addedge(int u,int v,double w){E[u].push_back(Edge(v,w));} 26 bool vis[MAXN]; 27 int cnt[MAXN]; 28 double dis[MAXN]; 29 bool SPFA(int start,int n){ 30 memset(vis,false,sizeof vis); 31 for(int i=1;i<=n;i++) dis[i] = 0; 32 vis[start]=true,dis[start]=1; 33 queue<int> q;q.push(start); 34 memset(cnt,0,sizeof cnt);cnt[start] = 1; 35 while(q.size()){ 36 int u = q.front();q.pop(); 37 vis[u]=false; 38 for(int i=0;i<E[u].size();i++){ 39 int v = E[u][i].v; 40 if(dis[v]<dis[u]*E[u][i].cost){ 41 //cout<<u<<" "<<v<<" "<<dis[u]<<" "<<dis[v]<<" "<<dis[u]*E[u][i].cost<<" "<<E[u][i].cost<<endl; 42 dis[v]=dis[u]*E[u][i].cost; 43 if(v==start) return true; 44 if(!vis[v]){ 45 vis[v] = true; 46 q.push(v); 47 if(++cnt[v]>n) return true; 48 } 49 } 50 } 51 } 52 return false; 53 } 54 55 56 int main() 57 { 58 int n,m,cas=1; 59 while(cin>>n&&n){ 60 cout<<"Case "<<cas++<<": "; 61 mp.clear(); 62 for(int i=1;i<=n;i++){ 63 E[i].clear(); 64 string s;cin>>s; 65 mp[s]=i; 66 } 67 cin>>m; 68 while(m--){ 69 int a,b; 70 double c; 71 for(int i=0;i<3;i++){ 72 string s;cin>>s; 73 char ss[100]; 74 strcpy(ss,s.c_str()); 75 if(i==0) a = mp[s]; 76 else if(i==1) c = atof(ss); 77 else b = mp[s]; 78 } 79 //cout<<a<<" "<<b<<" "<<c<<endl; 80 addedge(a,b,c); 81 } 82 bool flag = true; 83 for(int i=1;i<=n&&flag;i++){ 84 if(SPFA(i,n)) flag=false; 85 } 86 if(flag) puts("No"); 87 else puts("Yes"); 88 } 89 return 0; 90 }
Invitation CardsPOJ - 1511
题意:点1是巴士总站,其余有n-1个站,每个n-1站点派一个人,给出路线,路线花费金额,问所有人从总站到站点再回总站的总费用最低为多少?
算法:SPFA
思路:这题,前面的一道题(牛参加派对)差不多;就是求一个站点1为起点的SPFA;然后逆序路径,求站点1为终点的SPFA;
易错点:路径用vector,每一次都需要clear(),容易超时,这里换个路径存储方式减少时间;然后不要用cin输入,用scanf;
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdio> 7 #include <map> 8 #include <math.h> 9 10 using namespace std; 11 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1000000+10; 14 15 struct Edge{ 16 int v,cost,next; 17 }; 18 Edge E1[MAXN],E2[MAXN]; 19 int head1[MAXN],head2[MAXN],num1,num2; 20 void addedge(int u,int v,int w){ 21 E1[num1].v = v , E1[num1].cost = w , E1[num1].next = head1[u] , head1[u] = num1++; 22 E2[num2].v = u , E2[num2].cost = w , E2[num2].next = head2[v] , head2[v] = num2++; 23 } 24 bool vis[MAXN]; 25 int dis1[MAXN],dis2[MAXN]; 26 bool SPFA(int start,int n,Edge E[MAXN],int head[MAXN],int (&dis)[MAXN]){ 27 memset(vis,false,sizeof vis); 28 for(int i=1;i<=n;i++) dis[i] = INF; 29 vis[start]=true,dis[start]=0; 30 queue<int> q;q.push(start); 31 while(q.size()){ 32 int u = q.front();q.pop(); 33 vis[u]=false; 34 for(int i=head[u];i!=-1;i=E[i].next){ 35 int v = E[i].v; 36 if(dis[v]>dis[u]+E[i].cost){ 37 dis[v]=dis[u]+E[i].cost; 38 if(!vis[v]){ 39 vis[v] = true; 40 q.push(v); 41 } 42 } 43 } 44 } 45 return true; 46 } 47 int main() 48 { 49 int _; 50 //cin>>_; 51 scanf("%d",&_); 52 while(_--){ 53 int n,m; 54 //cin>>n>>m; 55 scanf("%d%d",&n,&m); 56 num1 = num2 = 0; 57 memset(head1,-1,sizeof head1);memset(head2,-1,sizeof head2); 58 while(m--){ 59 int a,b,c; 60 //cin>>a>>b>>c; 61 scanf("%d%d%d",&a,&b,&c); 62 addedge(a,b,c); 63 } 64 long long ans = 0; 65 SPFA(1,n,E1,head1,dis1); 66 SPFA(1,n,E2,head2,dis2); 67 for(int i=1;i<=n;i++) ans += (dis1[i]+dis2[i]); 68 cout<<ans<<endl; 69 } 70 return 0; 71 }
CandiesPOJ - 3159
题意:班级有n个学生,进行分糖果,每个同学有个单向关系,(a,b,c):同学b的糖果 要小于等于(同学a的糖果+c);问满足所有关系的条件下,学生1与学生n之间最大糖果差是多少?
算法:差分约束 + dij / SPFA(栈)
思路:差分约束就是,每两个点之间关系是不等式,所有关系要转变成一个方向,最大值要小于等于求最短;最大值要大于等于求最长;然后这题求最短路径可以用DIJKSTRA算法,也可以用SPFA,但是这题用队列的话会TLE,用栈就能过;
我并没有用数据考察过,目前就只能这么理解;
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 6 using namespace std; 7 8 const int MAXN = 30000 + 10; 9 const int MAXM = 150000 + 10; 10 const int INF = 0x3f3f3f3f; 11 12 struct Edge{int v,cost,next;}E[MAXM]; 13 int head[MAXN],num; 14 void addedge(int u,int v,int w){E[num].v = v , E[num].cost = w , E[num].next = head[u] , head[u] = num++;} 15 16 struct node{ 17 int u,cost; 18 node(int a,int b):u(a),cost(b) {}; 19 bool operator < (const node &a)const{ 20 return cost > a.cost; 21 } 22 }; 23 bool vis[MAXN]; 24 int dist[MAXN]; 25 void Dijkstra(int start,int n){ 26 memset(vis,false,sizeof vis); 27 memset(dist,INF,sizeof dist);dist[start] = 0; 28 priority_queue<node> q;q.push(node(start,0)); 29 while(q.size()){ 30 node p = q.top();q.pop(); 31 int u = p.u; 32 if(vis[u]) continue; 33 vis[u] = true; 34 for(int i = head[u];i != -1;i = E[i].next){ 35 int v = E[i].v , cost = E[i].cost; 36 if(dist[v] > dist[u] + cost){ 37 dist[v] = dist[u] + cost; 38 q.push(node(v,dist[v])); 39 } 40 } 41 } 42 } 43 44 int main(){ 45 int n,m;scanf("%d%d",&n,&m); 46 num=0;memset(head,-1,sizeof head); 47 while(m--){ 48 int a,b,c;scanf("%d%d%d",&a,&b,&c); 49 addedge(a,b,c); 50 } 51 Dijkstra(1,n); 52 cout<<dist[n]<<endl; 53 }
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <stack> 6 7 using namespace std; 8 9 const int MAXN = 30000 + 10; 10 const int MAXM = 150000 + 10; 11 const int INF = 0x3f3f3f3f; 12 13 struct Edge{int v,cost,next;}E[MAXM]; 14 int head[MAXN],num; 15 void addedge(int u,int v,int w){E[num].v = v , E[num].cost = w , E[num].next = head[u] , head[u] = num++;} 16 17 bool vis[MAXN]; 18 int dist[MAXN],cnt[MAXN]; 19 bool SPFA(int start,int n){ 20 memset(vis,false,sizeof vis);vis[start] = true; 21 memset(dist,INF,sizeof dist);dist[start] = 0; 22 memset(cnt,0,sizeof cnt);cnt[start] = 1; 23 stack<int> q;q.push(start); 24 while(q.size()){ 25 int u = q.top();q.pop(); 26 vis[u] = false; 27 for(int i = head[u];i != -1;i = E[i].next){ 28 int v = E[i].v, cost = E[i].cost; 29 if(dist[v] > dist[u] + cost){ 30 dist[v] = dist[u] + cost; 31 if(vis[v]) continue; 32 vis[v] = true; 33 q.push(v); 34 if(++cnt[v]>n) return false; 35 } 36 } 37 } 38 return true; 39 } 40 41 int main(){ 42 int n,m;scanf("%d%d",&n,&m); 43 num=0;memset(head,-1,sizeof head); 44 while(m--){ 45 int a,b,c;scanf("%d%d%d",&a,&b,&c); 46 addedge(a,b,c); 47 } 48 SPFA(1,n); 49 cout<<dist[n]<<endl; 50 }
SubwayPOJ - 2502
题意:一个帅小伙搬到大城市住,上学都坐地铁了,所有点都是坐标表示,距离以米为单位,步行速度是10km/h,地铁都是双向的,速度为40km/h,点1是家,点2是学校,问从家到学校最短时间是多少?
算法:DIJKSTRA
思路:就存地铁的边,然后在遍历所有任意两点之间的距离存起来,然后跑一遍dij算法
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string.h> 5 #include <queue> 6 #include <vector> 7 #include <stack> 8 #include <cmath> 9 #include <map> 10 #include <limits.h> 11 #include <float.h> 12 13 using namespace std; 14 15 const int MAXN = 200 + 10; 16 const double INF = 0x3f3f3f3f; 17 18 struct Edge{ 19 int v; 20 double cost; 21 Edge(int a,double b):v(a),cost(b) {} 22 }; 23 vector<Edge> E[MAXN]; 24 void addedge(int u,int v,double w){E[u].push_back(Edge(v,w));E[v].push_back(Edge(u,w));} 25 26 bool vis[MAXN]; 27 double dist[MAXN]; 28 struct qnode{ 29 int v; 30 double cost; 31 qnode(int a,double b):v(a),cost(b) {} 32 bool operator < (const qnode &a)const{ 33 return cost > a.cost; 34 } 35 }; 36 void Dijkstra(int start,int n){ 37 memset(vis,false,sizeof vis); 38 for(int i=0;i<n;i++) dist[i] = DBL_MAX; 39 dist[start] = 0; 40 priority_queue<qnode> q;q.push(qnode(start,0)); 41 while(q.size()){ 42 qnode p = q.top();q.pop(); 43 int u = p.v; 44 if(vis[u]) continue; 45 vis[u] = true; 46 //cout<<u<<" "<<dist[u]<<endl; 47 for(int i = 0;i < E[u].size();i++){ 48 int v = E[u][i].v; 49 if(vis[v]) continue; 50 if(dist[v]>dist[u]+E[u][i].cost){ 51 dist[v] = dist[u] + E[u][i].cost; 52 q.push(qnode(v,dist[v])); 53 } 54 } 55 } 56 } 57 58 double getDis(int _a,int _b,int _c,int _d){ 59 double a = _a, b = _b , c = _c , d = _d; 60 a/=1000 , b/=1000 , c/=1000 , d/=1000; 61 double ans = (a-c)*(a-c)+(b-d)*(b-d); 62 return sqrt(ans); 63 } 64 65 66 int main(){ 67 int num = 0; 68 map<pair<int,int>,int> mp; 69 int nx[MAXN] , ny[MAXN]; 70 int x,y; 71 scanf("%d%d",&x,&y);nx[num]=x,ny[num]=y,mp[make_pair(x,y)] = num++; 72 scanf("%d%d",&x,&y);nx[num]=x,ny[num]=y; 73 if(mp.find(make_pair(x,y))!=mp.end()){puts("0");return 0;}mp[make_pair(x,y)] = num++; 74 while(scanf("%d%d",&x,&y)!=EOF){ 75 int faNum; 76 if(mp.find(make_pair(x,y))==mp.end()){ 77 nx[num] = x;ny[num] = y;mp[make_pair(x,y)] = num;faNum = num++; 78 }else faNum = mp[make_pair(x,y)]; 79 while(1){ 80 int a,b;scanf("%d%d",&a,&b); 81 if(a==-1&&b==-1) break; 82 int suNum; 83 if(mp.find(make_pair(a,b))==mp.end()){ 84 nx[num] = a;ny[num] = b;mp[make_pair(a,b)] = num;suNum = num++; 85 }else suNum = mp[make_pair(a,b)]; 86 //cout<<faNum<<" "<<suNum<<" "<<getDis(x,y,a,b)/40*60<<endl; 87 addedge(suNum,faNum,getDis(x,y,a,b)/40*60); 88 x = a, y = b,faNum = suNum; 89 } 90 } 91 for(int i=0;i<num;i++){ 92 x = nx[i] , y = ny[i]; 93 for(int j=i+1;j<num;j++){ 94 int a = nx[j] , b = ny[j]; 95 addedge(i,j,getDis(x,y,a,b)/10*60); 96 //cout<<i<<" "<<j<<" "<<x<<" "<<y<<" "<<a<<" "<<b<<" "<<getDis(x,y,a,b)/10*60<<endl; 97 } 98 } 99 Dijkstra(0,num); 100 printf("%.0f\n",dist[1]); 101 }
昂贵的聘礼POJ - 1062
题意:需要娶妻,但是不够钱,女方告诉你,你如果可以拿到某某物件,彩礼可以降至多少钱?然后你就开始了一个以物易物的道路,重点在于,存在一个m,只要你跟等级为x的人交易了,就不能跟等级和x差距超过m的人交易了。
算法:BFS
思路:这题看似最短路径,其实要考虑区间,其实是BFS;这里每个点存一个编号,一个区间、一个当前交易路径累积金额;答案要加一个当前物品的价值;这里如果需要剪枝,可以进行dis【当前节点编号】【left】【right】大小进行判重。我就没有进行判重,直接把所有可能性都跑一遍;然后我这里也是预先假设没有环的,再加上路径权都是非负数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string.h> 5 #include <queue> 6 #include <vector> 7 #include <stack> 8 #include <cmath> 9 #include <map> 10 #include <limits.h> 11 #include <float.h> 12 13 #define sc scanf 14 #define pf printf 15 #define REP(i,a,b) for(int i=(a);i<(b);i++) 16 #define CLR(x,m) memset(x,m,sizeof x); 17 #define LOCAL freopen("test.txt","r",stdin) 18 #define UCCU ios::sync_with_stdio(0); 19 #define XSD(i) cout << fixed << setprecision(i); 20 #define pii pair<int,int> 21 #define xx first 22 #define yy second 23 24 using namespace std; 25 26 typedef long long LL; 27 typedef unsigned long long ULL; 28 typedef double DB; 29 typedef long double LDB; 30 31 const double eps = 1e-8; 32 //const int inf = 1<<30; 33 const int INF = 0x3f3f3f3f; 34 const long long llinf = (long long)300100*1000000000; 35 const DB PI = acos(-1.0); 36 const LL mod = 1e9+7; 37 38 //----------------------------------------------------------------------- 39 const int MAXN = 100 + 10; 40 41 int n,m; 42 43 int level[MAXN],value[MAXN]; 44 struct Edge{ 45 int v,cost; 46 Edge(int a,int b):v(a),cost(b) {} 47 }; 48 vector<Edge> E[MAXN]; 49 void addedge(int u,int v,int cost){E[u].push_back(Edge(v,cost));} 50 bool checkLR(int index,int left,int right){ 51 return (left<=level[index]&&level[index]<=right); 52 } 53 54 struct node{ 55 int now, left , right, dis; 56 node(int a,int l,int r,int d):now(a),left(l),right(r),dis(d) {}; 57 }; 58 LL ans; 59 void SPFA(){ 60 int left = level[1] - m;if(left<0) left = 0; 61 int right = level[1] + m; 62 ans = value[1];//cout<<ans<<endl; 63 queue<node> q; 64 q.push(node(1,left, right, 0)); 65 66 while(q.size()){ 67 node p = q.front();q.pop(); 68 //cout<<"----------------------------------"<<endl; 69 //cout<<p.now<<" "<<p.left<<" "<<p.right<<" "<<p.dis<<endl; 70 int u = p.now; 71 for(int i=0;i<E[u].size();i++){ 72 int v = E[u][i].v; 73 if(!checkLR(v,p.left,p.right)) continue; 74 int dis = p.dis + E[u][i].cost; 75 if(p.dis + value[p.now] < dis ) continue; 76 if(ans < dis) continue; 77 int l = level[v] - m; if(l < 0 ) l = 0; 78 int r = level[v] + m; 79 if(p.left>l) l = p.left; 80 if(p.right<r) r = p.right; 81 if(ans>dis + value[v]) ans = dis + value[v];//cout<<ans<<endl;} 82 //cout<<v<<" "<<l<<" "<<r<<" "<<dis<<endl; 83 q.push(node(v,l,r,dis)); 84 } 85 } 86 } 87 88 89 90 void init(){ 91 cin>>m>>n; 92 for(int i=1;i<=n;i++){ 93 int x;cin>>value[i]>>level[i]>>x; 94 for(int j=0;j<x;j++){ 95 int a,b;cin>>a>>b; 96 addedge(i,a,b); 97 } 98 } 99 } 100 101 int main(){ 102 //LOCAL; 103 UCCU; 104 init(); 105 SPFA(); 106 cout<<ans<<endl; 107 return 0; 108 }
题意:N个岔路,给你两个岔路点A,B;问从A到B最少操作数是多少?每个岔路都只能走一个方向到一个特定的岔路,但是你可以通过一个操作改变方向到另一个岔路。如果不操作就能从A到B,答案为0;
算法:SPFA/DIJ
思路:这里关键在于建边,初始边的权值为0,其余皆为1;
易错点:这里无法到达,需要输出 -1
SPFA
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 100 + 10;
int n,a,b;
struct Edge{
int v,cost;
Edge(int a,int b):v(a),cost(b) {}
};
vector<Edge> E[MAXN];
void addedge(int u,int v,int cost){E[u].push_back(Edge(v,cost));}
int dis[MAXN];
bool vis[MAXN];
void SPFA(){
memset(vis,false,sizeof vis);
memset(dis,INF,sizeof dis);
dis[a] = 0;
vis[a] = true;
queue<int> q;
q.push(a);
while(q.size()){
int u = q.front();q.pop();
vis[u] = false;
for(int i = 0;i<E[u].size();i++){
int v = E[u][i].v,cost = E[u][i].cost;
if(dis[v] > dis[u] + cost){
dis[v] = dis[u] + cost;
if(vis[v]) continue;
vis[v] = true;
q.push(v);
}
}
}
}
void init(){
cin>>n>>a>>b;
for(int i=1;i<=n;i++){
int len;cin>>len;
for(int j=0;j<len;j++){
int c;cin>>c;
if(j) addedge(i,c,1);
else addedge(i,c,0);
}
}
}
int main(){
//LOCAL;
UCCU;
init();
SPFA();
if(dis[b]==INF) puts("-1");
else cout<<dis[b]<<endl;
return 0;
}
DIJKSTRA
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 100 + 10;
int n,a,b;
struct Edge{
int v,cost;
Edge(int a,int b):v(a),cost(b) {}
};
vector<Edge> E[MAXN];
void addedge(int u,int v,int cost){E[u].push_back(Edge(v,cost));}
struct node{
int v, c;
node(int _v,int _c):v(_v),c(_c) {}
bool operator <(const node &r)const{
return c > r.c;
}
};
bool vis[MAXN];
int dist[MAXN];
int DIJKSTRA(){
memset(vis,false,sizeof vis);
memset(dist,INF,sizeof dist);
priority_queue<node> q;
dist[a] = 0;q.push(node(a,0));
while(q.size()){
node tmp = q.top();q.pop();
int u = tmp.v;
if(u == b) return dist[b];
if(vis[u]) continue;
vis[u] = true;
for(int i=0;i<E[u].size();i++){
int v = E[u][i].v , cost = E[u][i].cost;
if(!vis[v]&&dist[v] > dist[u] + cost){
dist[v] = dist[u] + cost;
q.push(node(v,dist[v]));
}
}
}
return -1;
}
void init(){
cin>>n>>a>>b;
for(int i=1;i<=n;i++){
int len;cin>>len;
for(int j=0;j<len;j++){
int c;cin>>c;
if(j) addedge(i,c,1);
else addedge(i,c,0);
}
}
}
int main(){
//LOCAL;
UCCU;
init();
cout<<DIJKSTRA()<<endl;
return 0;
}
Extended Traffic LightOJ - 1074
题意:给你n个点,每个点有个拥堵值,m条单向边,权值为(目的拥堵值-出发拥堵值)的立方——因为是立方,所以存在负值边,存在负环;起点永远是点1,然后进行多次查询,每次输入目的点,求到目的点最短路径;如果路径值小于3或者无法到达输出?
算法:SPFA
思路:这里用SPFA求出,从起点1到所有点距离,一次SPFA就可以应对多次查询。
查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 200 + 10;
struct Edge{
int v,cost;
Edge(int a,int b):v(a),cost(b) {}
};
vector<Edge> E[MAXN];
void addedge(int u,int v,int cost){E[u].push_back(Edge(v,cost));}
int n,m,k;
int level[MAXN];
bool vis[MAXN];
int dist[MAXN],cnt[MAXN];
bool SPFA(){
memset(vis,false,sizeof vis);
memset(dist,INF,sizeof dist);
memset(cnt,0,sizeof cnt);
queue<int> q;
dist[1] = 0;vis[1]=true;cnt[1] = 1;
q.push(1);
while(q.size()){
int u = q.front();q.pop();
vis[u] = false;
for(int i=0;i<E[u].size();i++){
int v = E[u][i].v , cost = E[u][i].cost;
if(dist[v] > dist[u] + cost){
dist[v] = dist[u] + cost;
if(vis[v]||cnt[v]>n-1) continue;
vis[v] = true;
q.push(v);
++cnt[v];
}
}
}
return true;
}
void init(){
cin>>n;
for(int i=1;i<=n;i++) {E[i].clear();cin>>level[i];}
cin>>m;
for(int i=0;i<m;i++){
int a,b;cin>>a>>b;
int c = level[b] - level[a];
addedge(a,b,c*c*c);
}
}
int main(){
//LOCAL;
UCCU;
int _,cas = 1;cin>>_;
while(_--){
cout<<"Case "<<cas++<<":"<<endl;
init();
SPFA();
cin>>k;
while(k--){
int a;cin>>a;
if(dist[a]<3||dist[a]==INF||cnt[a]>n-1) cout<<"?"<<endl;
else cout<<dist[a]<<endl;
}
}
return 0;
}
The Shortest Path in Nya Graph HDU - 4725
题意:给你n个点,多层地图,每一层可能包含多个点,或者没有点;邻层之间的点可以联通,代价为c;然后存在其他m条边连同不同层;
算法:dijkstra、spfa
难点:这里关键就是建图;每一层都新建一个点,这个点单向到自己这个层的代价为0;然后上下两层到这个点代价为c;
查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 2*1e5 + 10;
const int MAXM = 5*1e5 + 10;
struct Edge{
int v,cost;
Edge(int a,int b):v(a),cost(b) {}
};
vector<Edge> E[MAXM];
void addedge(int u,int v,int cost){E[u].push_back(Edge(v,cost));}
struct node{
int u,cost;
node(int a,int b):u(a),cost(b) {};
bool operator < (const node &a)const{
return cost > a.cost;
}
};
bool vis[MAXN],islayer[MAXN/2];
int dist[MAXN],layer[MAXN/2];
void Dijkstra(int start,int n){
for(int i=1;i<=n+n;i++) vis[i]=false,dist[i]=INF;
dist[start] = 0;
priority_queue<node> q;q.push(node(start,0));
while(q.size()){
node p = q.top();q.pop();
int u = p.u;
if(vis[u]) continue;
vis[u] = true;
if(u == n) break;
for(int i=0;i<E[u].size();i++){
int v = E[u][i].v , cost = E[u][i].cost;
if(dist[v] > dist[u] + cost){
dist[v] = dist[u] + cost;
q.push(node(v,dist[v]));
}
}
}
}
int n;
void init(){
int m,c;
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=n+n;i++){
if(i<=n) islayer[i] = false;
E[i].clear();
}
for(int i=1;i<=n;i++) {scanf("%d",&layer[i]);islayer[layer[i]]=true;}
for(int i=1;i<=n;i++){
int a = layer[i];
addedge(n+a,i,0);
if(a-1>=1&&islayer[a-1]) addedge(i,n+a-1,c);
if(a+1<=n&&islayer[a+1]) addedge(i,n+a+1,c);
}
for(int i=0;i<m;i++){
int a,b,d;scanf("%d%d%d",&a,&b,&d);
addedge(a,b,d);addedge(b,a,d);
}
}
int main(){
//LOCAL;
//UCCU;
//cin.tie(0);
//cout.tie(0);
int _,cas = 1;
scanf("%d",&_);
while(_--){
init();
Dijkstra(1,n);
int ans = dist[n]==INF?-1:dist[n];
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}
查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 2*1e5 + 10;
const int MAXM = 5*1e5 + 10;
struct Edge{int v,cost,next;}E[MAXM];
int head[MAXN],num;
void addedge(int u,int v,int cost){E[num].v = v,E[num].cost = cost,E[num].next = head[u],head[u]=num++;}
struct node{
int u,cost;
node(int a,int b):u(a),cost(b) {};
bool operator < (const node &a)const{
return cost > a.cost;
}
};
bool vis[MAXN],islayer[MAXN/2];
int dist[MAXN],layer[MAXN/2];
void Dijkstra(int start,int n){
memset(vis,false,sizeof vis);
memset(dist,INF,sizeof dist);
dist[start] = 0;
priority_queue<node> q;q.push(node(start,0));
while(q.size()){
node p = q.top();q.pop();
int u = p.u;
if(vis[u]) continue;
vis[u] = true;
if(u == n) break;
for(int i = head[u];i != -1;i = E[i].next){
int v = E[i].v , cost = E[i].cost;
if(dist[v] > dist[u] + cost){
dist[v] = dist[u] + cost;
q.push(node(v,dist[v]));
}
}
}
}
int n;
void init(){
int m,c;
//cin>>n>>m>>c;
scanf("%d%d%d",&n,&m,&c);
num = 0;
for(int i=1;i<=n+n;i++){
if(i<=n) islayer[i] = false;
head[i] = -1;
}
for(int i=1;i<=n;i++) {
//cin>>layer[i];
scanf("%d",&layer[i]);
islayer[layer[i]]=true;
}
for(int i=1;i<=n;i++){
int a = layer[i];
addedge(n+a,i,0);
if(a-1>=1&&islayer[a-1]) addedge(i,n+a-1,c);
if(a+1<=n&&islayer[a+1]) addedge(i,n+a+1,c);
}
for(int i=0;i<m;i++){
int a,b,d;
//cin>>a>>b>>d;
scanf("%d%d%d",&a,&b,&d);
addedge(a,b,d);addedge(b,a,d);
}
}
int main(){
//LOCAL;
//UCCU;
//cin.tie(0);
//cout.tie(0);
int _,cas = 1;
//cin>>_;
scanf("%d",&_);
while(_--){
init();
Dijkstra(1,n);
//cout<<"Case #"<<cas++<<": "<<dist[n]<<endl;
int ans = dist[n]==INF?-1:dist[n];
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}
查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 2*1e5 + 10;
const int MAXM = 5*1e5 + 10;
struct Edge{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {}
};
vector<Edge> E[MAXN];
void addedge(int u,int v,int w){E[u].push_back(Edge(v,w));}
bool vis[MAXN];
int cnt[MAXN],dis[MAXN];
bool SPFA(int start,int n){
memset(vis,false,sizeof vis);
for(int i=1;i<=n+n;i++) dis[i] = INF;
vis[start]=true,dis[start]=0;
queue<int> q;q.push(start);
memset(cnt,0,sizeof cnt);cnt[start] = 1;
while(q.size()){
int u = q.front();q.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++){
int v = E[u][i].v;
if(dis[v]>dis[u]+E[u][i].cost){
dis[v]=dis[u]+E[u][i].cost;
if(!vis[v]){
vis[v] = true;
q.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
int n;
bool islayer[MAXN/2];
int layer[MAXN/2];
void init(){
int m,c;
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=n+n;i++){
if(i<=n) islayer[i] = false;
E[i].clear();
}
for(int i=1;i<=n;i++) {scanf("%d",&layer[i]);islayer[layer[i]]=true;}
for(int i=1;i<=n;i++){
int a = layer[i];
addedge(n+a,i,0);
if(a-1>=1&&islayer[a-1]) addedge(i,n+a-1,c);
if(a+1<=n&&islayer[a+1]) addedge(i,n+a+1,c);
}
for(int i=0;i<m;i++){
int a,b,d;scanf("%d%d%d",&a,&b,&d);
addedge(a,b,d);addedge(b,a,d);
}
}
int main(){
//LOCAL;
//UCCU;
//cin.tie(0);
//cout.tie(0);
int _,cas = 1;
scanf("%d",&_);
while(_--){
init();
SPFA(1,n);
//for(int i=1;i<=n;i++) cout<<dis[i]<<endl;
int ans = dis[n]==INF?-1:dis[n];
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}
Marriage Match IVHDU - 3416
题意:n个城市,m条道路,每条道路只能走一次,每条边有个费用c,给你一个起点s,终点t;然后男主角必须从s开始走最短路径(最小费用)到t,问有多少次机会,即存在多少条互不影响的最短路径;
算法:预处理+最大流
思路:这里我一开始用最小费用最大流,然后TLE;然后想到对于求最大流进行减枝预处理,类似于Destroying the bus stationsHDU - 2485这道题,把不符合答案的边剔除掉,只保留答案边。因为这里必须是最短路径,那就跑一次spfa,求出每个点到起点的距离,如果dis[u] + c ==dis[v],那么(u,v,c)这个边就是最短路径里的一条边,加入到最大流图里;然后跑一次最大流;
查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 1000 + 10;
const int MAXM = 200000 + 10;
struct Edge{
int to,next,cap,flow;
}edge[MAXM];
int tol,head[MAXN];
void init(){
tol = 2;
memset(head, -1, sizeof head);
}
void addedge(int u,int v,int w,int rw = 0){
edge[tol].to = v;edge[tol].cap = w;edge[tol].flow = 0;
edge[tol].next = head[u];head[u] = tol++;
edge[tol].to = u;edge[tol].cap = rw;edge[tol].flow = 0;
edge[tol].next = head[v];head[v] = tol++;
}
int Q[MAXN];
int dep[MAXN],cur[MAXN],sta[MAXN];
bool bfs(int s,int t,int n){
int front = 0,tail = 0;
memset(dep, -1, sizeof(dep[0])*(n+1));
dep[s] = 0;
Q[tail++] = s;
while(front < tail){
int u = Q[front++];
for(int i = head[u];i != -1;i = edge[i].next){
int v = edge[i].to;
if(edge[i].cap > edge[i].flow && dep[v] == -1){
dep[v] = dep[u] + 1;
if(v == t) return true;
Q[tail++] = v;
}
}
}
return false;
}
int dinic(int s,int t,int n){
int maxflow = 0;
while(bfs(s,t,n)){
for(int i=0;i<n;i++) cur[i] = head[i];
int u = s,tail = 0;
while(cur[s] != -1){
if(u == t){
int tp = INF;
for(int i=tail-1;i>=0;i--) tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
maxflow+=tp;
for(int i=tail-1;i>=0;i--){
edge[sta[i]].flow+=tp;
edge[sta[i]^1].flow-=tp;
if(edge[sta[i]].cap-edge[sta[i]].flow==0) tail = i;
}
u = edge[sta[tail]^1].to;
}else if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] +1 ==dep[edge[cur[u]].to]){
sta[tail++] = cur[u];
u = edge[cur[u]].to;
}else{
while(u != s && cur[u] == -1) u = edge[sta[--tail]^1].to;
cur[u] = edge[cur[u]].next;
}
}
}
return maxflow;
}
struct node{
int v,c;
node(int vv,int cc):v(vv),c(cc) {}
};
vector<node> E[MAXN];
int dis[MAXN];
bool vis[MAXN];
void SPFA(int start,int n,int (&dis)[MAXN],bool vis[MAXN],vector<node> E[MAXN]){
vis[start]=true,dis[start]=0;
queue<int> q;q.push(start);
while(q.size()){
int u = q.front();q.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++){
int v = E[u][i].v,c = E[u][i].c;
if(dis[v]>dis[u]+c){
dis[v]=dis[u]+c;
if(!vis[v]){
vis[v] = true;
q.push(v);
}
}
}
}
}
int n,m,s,t;
bool init_2(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
dis[i] = INF;
vis[i] = false;
E[i].clear();
}
for(int i=0;i<m;i++){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
if(a==b) continue;
E[a-1].push_back(node(b-1,c));
}
scanf("%d%d",&s,&t);
s--,t--;
SPFA(s,n,dis,vis,E);
if(dis[t]==INF) return false;
init();
for(int i=0;i<n;i++){
for(int j=0;j<E[i].size();j++){
int v = E[i][j].v;
if(dis[i] + E[i][j].c == dis[v]) addedge(i,v,1);
}
}
return true;
}
int main(){
int _;scanf("%d",&_);
while(_--){
if(!init_2()) puts("0");
else printf("%d\n",dinic(s,t,n));
}
return 0;
}
R - 0 or 1HDU - 4370
题意:给你一个n*n矩阵C,然后n*n矩阵X只能是0或者1,问你矩阵这么填充数字,满足以下所有条件
1.X12+X13+...X1n=1
2.X1n+X2n+...Xn-1n=1
3.for each i (1<i<n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n).
并且 ∑Cij*Xij(1<=i,j<=n) 最小
算法:矩阵转换路径图条件(构图)+SPFA
思路:因为之前做了dancingLink,导致我往那边想,当我越陷越深,才发现我做的是一道最短路径题,我就想着往图那边想;但是趋于自己过于愚笨,最后还是百度借鉴他人思路;大佬博客:https://www.cnblogs.com/xiongtao/p/10318440.html
以下是我看完自己的想法;
第一:考虑X(i,i) ,条件1,2没涉及 ,条件3涉及,但是左右两边都有,相减就不涉及了,所以X(i,i)都设置为0,都满足条件1,2,3;并且使得∑Cij*Xij(1<=i,j<=n)更小了。这里其实间接表示,这张图,没有必要存在自身点连接的边;
第二:把矩阵X看成一个图的边邻接矩阵,1表示这个单向边存在,0表示这个单向边不存在;则矩阵C表示这个边的费用;那么条件1,代表的意思就是,点1出去的边有且仅有一条,并且只能是其他点——出度为1;同理条件2,代表的意思就是,点n进来的边有且仅有一条,并且只能是其他点——入度为1;条件3,则表示对于for each i (1<i<n),点i有多少边进来就有多少边出去——点i的出入度都相等——点i不可能作为联通路径的结束点或者起始点;所以有个起点一定是点1,结束点为n的路径————点1必须是一条路的起点,点n必须是一条路的终点;但对于点1入度的和点n出度没规定,所以存在两种情况:
第一情况:这张图存在一个1到n的路径,因为答案要求最小,所以这个路径必须费用最小且不成环;第二情况:存在一个1到1自己的路径环,并且n到n自己的路径环,两条环路(因为点1必须是一条路的起点,点n必须是一条路的终点),并且这两个环总费用要最低;
所以答案就是两种情况的最小值;
解决办法:这里将X12、X13、...X1n加进队列,跑一次点1为起点的SPFA,因为这些边都是互斥——所有可能性都进一次队列且图所有边都是正向边,所以跑出最短路径dis[n]就是情况1费用,且dis[1]为1自环路径的最短路径费用;同理跑一次点n为起点的SPFA,dis[n]为n自环路径的最短路径费用;答案就是,min(SPFA1_dis[n], SPFA1_dis[1]+SPFAN_dis[n])
查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
int C[303][303],n;
int dis[303];
bool vis[303];
void SPFA(int start){
queue<int> q;
for(int i=1;i<=n;i++){
if(i==start) dis[i] = INF,vis[i] = false;
else dis[i] = C[start][i],vis[i] = true,q.push(i);
}
while(q.size()){
int u = q.front();q.pop();
vis[u] = false;
for(int i=1;i<=n;i++){
if(i==u) continue;
if(dis[i]>dis[u]+C[u][i]){
dis[i]=dis[u]+C[u][i];
if(!vis[i]){
vis[i] = true;
q.push(i);
}
}
}
}
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) scanf("%d",&C[i][j]);
SPFA(1);
int ans = dis[n],tmp = dis[1];
SPFA(n);
ans = min(ans, tmp+dis[n]);
printf("%d\n",ans);
}
return 0;
}
LayoutPOJ - 3169
题意:n个牛,然后每个牛有两种逻辑关系:
Lines 2..ML+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at most D (1 <= D <= 1,000,000) apart.
A牛和B牛最多相距D远 B <= A + D
Lines ML+2..ML+MD+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at least D (1 <= D <= 1,000,000) apart.
A牛和B牛最多至少D远 A <= B - D
算法:差分约束+SPFA
思路:这题与之前糖果题目—— CandiesPOJ - 3159 思路一模一样;但是我这里wrong了几次,只是因为题目中写了,牛会按照编号顺序那样排号,但是可以多个牛在同一位置,即顺序关系不变,但是一个坑可以多牛站;但是如果我在结果如果加上顺序判断的时候,就会wrong;如果删掉就会accept!!
查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <limits.h>
#include <float.h>
#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
typedef long double LDB;
const double eps = 1e-8;
//const int inf = 1<<30;
const int INF = 0x3f3f3f3f;
const long long llinf = (long long)300100*1000000000;
const DB PI = acos(-1.0);
const LL mod = 1e9+7;
//-----------------------------------------------------------------------
const int MAXN = 1000 + 10;
//const int MAXM = 2000 + 10;
struct edge{
int v,w;
edge(int vv,int ww):v(vv),w(ww) {}
};
vector<edge> Edge[MAXN];
void addedge(int u,int v,int w){Edge[u].push_back(edge(v,w));}
int dis[MAXN], cnt[MAXN];
bool vis[MAXN];
bool SPFA(int n){
queue<int> q;
dis[1] = 0;vis[1] = true;cnt[1]=1;q.push(1);
for(int i=2;i<=n;i++){
dis[i] = INF,vis[i] = false,cnt[i]=0;
}
while(q.size()){
int u = q.front();q.pop();
vis[u] = false;
for(int i=0;i<Edge[u].size();i++){
int v = Edge[u][i].v, w = Edge[u][i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
//if(dis[v]<0) return false;
if(!vis[v]){
if(++cnt[v]>n) return false;
vis[v] = true;
q.push(v);
}
}
}
}
//for(int i=2;i<=n;i++) if(dis[i]<dis[i-1]) return false;
return true;
}
int main(){
int n,m,k;scanf("%d%d%d",&n,&m,&k);
while(m--){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
}
while(k--){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
addedge(b,a,-c);
}
if(!SPFA(n)) puts("-1");
else if(dis[n]==INF) puts("-2");
else printf("%d\n",dis[n]);
return 0;
}
最后一行。。谢谢观看