周更1(最短路)
1、POJ - 1062 昂贵的聘礼
题意:你想娶酋长的女儿,但酋长要求你给一定数额金钱的聘礼。除了金钱外,酋长也允许你用部落里其他人的某物品加上一点钱作为聘礼。而其他人的物品也可以通过指定的另外一些人的某物品加上一些金钱获得。部落里的每个人有一个等级。你的整个交易过程涉及的人的等级只能在一个限定的差值内。问你最少需要多少金钱才能娶到酋长女儿。假定每个人只有一个物品。
思路:对冒险者的等级进行枚举,冒险者只能和在他等级以上的人进行交易。这样枚举的好处是能够把所有的情况都考虑进去。
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 6 const int INF=0x3f3f3f3f; 7 int map[200][200],n,m; 8 int vis[2000100],dis[1001000],sum=0; 9 int rankk[100100],val[1010000]; 10 11 int check(int x) //判断是否能交换成功 12 { 13 if(rankk[x]>=rankk[0]&&rankk[x]-rankk[0]<=m||m==0) return true; 14 return false; 15 16 } 17 18 int dijkstra() 19 { 20 for(int i=1;i<=n;i++){ 21 dis[i]=val[i]; 22 vis[i]=0; 23 } 24 int j,k,tmp; 25 for(int i=1;i<=n;i++){ 26 tmp=INF; 27 for(int j=1;j<=n;j++){ 28 if(!vis[j]&&tmp>dis[j]){ 29 k=j; 30 tmp=dis[j]; 31 } 32 } 33 if(tmp==INF) break; 34 vis[k]=1; 35 if(!check(k)) continue; 36 for(int j=1;j<=n;j++) 37 if(!vis[j]&&check(j)&&dis[j]>dis[k]+map[k][j]) 38 dis[j]=dis[k]+map[k][j]; 39 } 40 return dis[1]; 41 } 42 43 int main() 44 { 45 int x,a,b; 46 cin>>m>>n; 47 for(int i=1;i<=n;i++){ 48 for(int j=1;j<=n;j++){ 49 map[i][j]=INF; 50 } 51 map[i][i]=0; 52 } 53 for(int i=1;i<=n;i++){ 54 cin>>val[i]>>rankk[i]>>x; 55 while(x--){ 56 cin>>a>>b; 57 map[a][i]=b; 58 } 59 } 60 int ans=INF; 61 for(int i=1;i<=n;i++){ //对冒险者的等级进行枚举 62 rankk[0]=rankk[i]; 63 ans=min(ans,dijkstra()); 64 } 65 printf("%d\n",ans); 66 return 0; 67 }
2、HDU - 4370 0 or 1
题意:
给定一个 n*n 的矩阵 C,构造一个符合以下条件的矩阵 X:
1、X12+X13+...+X1n=1
2、X1n+X2n+...+X(n−1)n=1
3、∑Xki=∑Xij (1<k<n,1<=j<=n)
求 ∑i=i,j=1nCij∗Xij 的最小值。
思路:
1、表示点 1 的出度为 1
2、表示点 n 的入度为 1
3、除了点 1 和点 n 外的其他点出入度相等
故有答案两种情况,一种情况是从1~n跑一遍最短路,另一种是从1出发,走一个环(不能是自环),回到1;从n出发,走一个环,回到n。求两种情况中最短的路。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 7 const ll INF=1e9; 8 const int N=310; 9 10 int n,vis[N]; 11 ll map[N][N],dis[N]; 12 13 void Dijkstra(int src){ 14 int i; 15 for(i=1;i<=n;i++){ 16 dis[i]=map[src][i]; 17 vis[i]=0; 18 } 19 dis[src]=INF; 20 int j,k,tmp; 21 for(i=1;i<=n;i++){ 22 tmp=INF; 23 for(j=1;j<=n;j++) 24 if(!vis[j] && tmp>dis[j]){ 25 k=j; 26 tmp=dis[j]; 27 } 28 vis[k]=1; 29 for(j=1;j<=n;j++) 30 if(!vis[j] && dis[j]>dis[k]+map[k][j]) 31 dis[j]=dis[k]+map[k][j]; 32 } 33 } 34 35 int main() 36 { 37 while(scanf("%d",&n)!=EOF){ 38 for(int i=1;i<=n;i++) 39 for(int j=1;j<=n;j++) 40 scanf("%lld",&map[i][j]); 41 Dijkstra(1); 42 ll m=dis[1]; 43 ll ans=dis[n]; 44 Dijkstra(n); 45 ans=min(m+dis[n],ans); 46 printf("%lld\n",ans); 47 } 48 return 0; 49 }
3、POJ - 1847 Tram
题意:在一个交通网络上有N个路口, 每个路口指向多个方向, 默认驶向第一个方向, 驶向其他方向时需要进行一次操作, 求从a到b最小的操作数。
思路:第一组初始设为0,后边的要改方向的路径权值为1,到不了的为INF,求最短路。
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<string.h> 5 #define ll long long 6 using namespace std; 7 8 const int N = 200; 9 const int INF = 0x3f3f3f3f; 10 int map[N][N],dis[N],vis[N]; 11 int n,x,y; 12 13 void Dijkstra(int src){ 14 int i; 15 for(i=1;i<=n;i++){ 16 dis[i]=map[src][i]; 17 vis[i]=0; 18 } 19 dis[src]=0; 20 vis[src]=1; 21 int j,k,tmp; 22 for(i=1;i<=n;i++){ 23 tmp=INF; 24 for(j=1;j<=n;j++) 25 if(!vis[j] && tmp>dis[j]){ 26 k=j; 27 tmp=dis[j]; 28 } 29 if(tmp==INF) 30 break; 31 vis[k]=1; 32 for(j=1;j<=n;j++) 33 if(!vis[j] && dis[j]>dis[k]+map[k][j]) 34 dis[j]=dis[k]+map[k][j]; 35 } 36 } 37 38 int main() 39 { 40 scanf("%d%d%d",&n,&x,&y); 41 int b,c; 42 for(int i=1;i<=n;i++){ 43 for(int j=1;j<=n;j++) 44 map[i][j]=INF; 45 map[i][i]=0; 46 } 47 for(int i=1;i<=n;i++){ 48 scanf("%d",&b); 49 for(int j=0;j<b;j++){ 50 scanf("%d",&c); 51 if(j==0) map[i][c]=0; 52 else map[i][c]=1; 53 } 54 } 55 Dijkstra(x); 56 if(dis[y]==INF) printf("-1\n"); 57 else printf("%d\n",dis[y]); 58 return 0; 59 }
4、POJ - 3259 Wormholes
题意:是否能通过虫洞回到过去;虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退。我们把虫洞看成是一条负权路,问题就转化成求一个图中是否存在负权回路;
思路:简单的Bellman-Ford算法求负环
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 using namespace std; 5 6 int n,m,p; 7 const int INF=0x3f3f3f3f; 8 const int N=600; 9 int map[N][N]; 10 11 bool floyd() 12 { 13 for(int k=1;k<=n;k++){ 14 for(int i=1;i<=n;i++){ 15 for(int j=1;j<=n;j++){ 16 if(map[i][k]+map[k][j]<map[i][j]) 17 map[i][j]=map[i][k]+map[k][j]; 18 } 19 if(map[i][i]<0) return true; 20 } 21 } 22 return false; 23 } 24 25 int main() 26 { 27 int t; 28 scanf("%d",&t); 29 while(t--){ 30 scanf("%d%d%d",&n,&m,&p); 31 for(int i=1;i<=n;i++){ 32 for(int j=1;j<=n;j++){ 33 map[i][j]=INF; 34 } 35 map[i][i]=0; 36 } 37 int u,v,w; 38 for(int i=2;i<=m+1;i++){ 39 scanf("%d%d%d",&u,&v,&w); 40 map[u][v]=map[v][u]=w; 41 } 42 for(int i=m+2;i<=m+p+1;i++){ 43 scanf("%d%d%d",&u,&v,&w); 44 map[u][v]=-w; 45 } 46 if(floyd()) printf("YES\n"); 47 else printf("NO\n"); 48 } 49 return 0; 50 }
5、POJ - 1797 Heavy Transportation
题意:N个点,M条边,每条边有权值。求一条1号点到N号点的路径,要求使得路径中的边权最小值最大。
思路:重点是维护dis数组,dis[j]=max(dis[j],min(dis[k],map[k][j]))。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 const int INF=1e7; 7 const int N=1001; 8 int maxn; 9 int n,m,s,t; 10 int map[N][N],dis[N],vis[N]; 11 12 void Dijkstra(int src){ 13 int i; 14 for(i=1;i<=n;i++){ 15 dis[i]=map[src][i]; 16 vis[i]=0; 17 } 18 dis[src]=0; 19 vis[src]=1; 20 int j,k; 21 for(i=1;i<=n;i++){ 22 k=-1; 23 maxn=0; 24 for(j=1;j<=n;j++) 25 if(!vis[j] && maxn<dis[j]){ 26 k=j; 27 maxn=dis[j]; 28 } 29 if(k==n) return; 30 vis[k]=1; 31 for(j=1;j<=n;j++) 32 if(!vis[j]){ 33 dis[j]=max(dis[j],min(dis[k],map[k][j])); //维护dis数组 34 } 35 } 36 } 37 38 int main() 39 { 40 int t; 41 cin>>t; 42 int k=0; 43 while(t--){ 44 k++; 45 scanf("%d%d",&n,&m); 46 int u,v,w; 47 maxn=0; 48 for(int i=1;i<=n;i++) 49 for(int j=1;j<=n;j++) 50 map[i][j]=-1; 51 for(int i=0;i<m;i++){ 52 scanf("%d%d%d",&u,&v,&w); 53 map[u][v]=map[v][u]=w; 54 } 55 Dijkstra(1); 56 printf("Scenario #%d:\n%d\n",k,dis[n]); 57 if(t) printf("\n"); 58 } 59 return 0; 60 }
6、POJ - 1860 Currency Exchange
题意:有多种汇币,汇币之间可以交换,这需要手续费,问s币的金额经过交换最终得到的s币金额数能否增加(货币的交换是可以重复多次的)。
思路:链式前向星存图+Bellman-Ford算法求是否有正环
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 #include<queue> 6 using namespace std; 7 8 double x; 9 const double INF = 1e7+1.0; 10 const int maxv=210; 11 int n, m, s,tot; 12 double dis[maxv]; 13 14 struct Edge 15 { 16 int u,v; 17 double w,c; 18 }edge[maxv]; 19 20 void addege(int u,int v,double w,double c) 21 { 22 edge[tot].u=u; 23 edge[tot].v=v; 24 edge[tot].w=w; 25 edge[tot].c=c; 26 tot++; 27 } 28 29 int Bellman_Ford(int s) 30 { 31 memset(dis, 0, sizeof(dis)); 32 dis[s]=x; 33 for (int k = 1; k <= n ; k++) 34 for (int i = 0; i < tot; i++){ 35 int u = edge[i].u, v = edge[i].v; 36 double w = edge[i].w,c = edge[i].c; 37 dis[v] =max(dis[v],(dis[u]-c)*w); 38 } 39 for(int i=0;i<tot;i++){ 40 int u = edge[i].u, v = edge[i].v; 41 double w = edge[i].w,c = edge[i].c; 42 if(dis[v]<(dis[u]-c)*w) return true; 43 } 44 return false; 45 } 46 47 int main() 48 { 49 scanf("%d%d%d%lf",&n,&m,&s,&x); 50 tot=0; 51 while(m--){ 52 int a,b; 53 double r1,r2,c1,c2; 54 scanf("%d%d%lf%lf%lf%lf",&a,&b,&r1,&c1,&r2,&c2); 55 addege(a,b,r1,c1); 56 addege(b,a,r2,c2); 57 } 58 int p=Bellman_Ford(s); 59 if(p) printf("YES\n"); 60 else printf("NO\n"); 61 return 0; 62 }