dijkstra算法(到一点的最短路)
void dijkstra(int s){ //到s点的最短路
for(int i=1;i<=n;i++){
dis[i]=a[s][i]; //先记录每个点到s的距离
}
vis[s]=1;
dis[s]=0;
for(int i=0;i<n;i++){ //找到n个点到s的最短距离
int flag=-1,Min=Inf;
for(int j=1;j<=n;j++){ //找到当前没有记录的点中到s的最短距离点
if(!vis[j]&&dis[j]<Min){
flag=j;
Min=dis[j];
}
}
vis[flag]=1;
for(int j=1;j<=n;j++){ //比较其他点直接到s的距离与其他点先到flag再到s的距离
if(a[flag][j]==Inf)continue;
if(!vis[j]&&dis[j]>Min+a[flag][j]){//如果距离更小就更新距离
dis[j]=Min+a[flag][j];
}
}
}
}
POJ 2387 Til the Cows Come Home
题意:有n块地,有t条路,找到1~n的最短距离
#include<stdio.h>
#include<string.h>
#define Inf 1e9+7
int a[1005][1005],dis[1005],t,n,vis[1005];
void dijkstra(int s){
for(int i=1;i<=n;i++){
dis[i]=a[s][i];
}
vis[s]=1;
dis[s]=0;
for(int i=0;i<n;i++){
int flag=-1,Min=Inf;
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]<Min){
flag=j;
Min=dis[j];
}
}
if(flag==n)return; //找到n到1的最短路直接返回
vis[flag]=1;
for(int j=1;j<=n;j++){
if(a[flag][j]==Inf)continue;
if(!vis[j]&&dis[j]>Min+a[flag][j]){
dis[j]=Min+a[flag][j];
}
}
}
}
int main(){
scanf("%d%d",&t,&n);
memset(a,Inf,sizeof(a));
for(int i=0;i<t;i++){
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
if(d<a[x][y])
a[x][y]=a[y][x]=d;
}
dijkstra(1);
printf("%d\n",dis[n]);
return 0;
}
POJ2253 Frogger
dijkstra算法的变形,把 if(!vis[j]&&dis[j]>Min+a[flag][j]) 更新距离这一步改为 if(!flag[j]&&dis[j]>max(Distance(j,k),Min)) 更新为由起点出发,到达j点需要的最大跳跃距离。
下面展示一些 内联代码片
。
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
int n,flag[205];
typedef struct a{
double x,y;
}aa;
aa a[205];
double dis[205];
double Distance(int xx,int yy){
return (a[xx].x-a[yy].x)*(a[xx].x-a[yy].x)+(a[xx].y-a[yy].y)*(a[xx].y-a[yy].y);
}
void dijkstra(int x){
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++){
dis[i]=(a[i].x-a[1].x)*(a[i].x-a[1].x)+(a[i].y-a[1].y)*(a[i].y-a[1].y);
}
for(int i=1;i<=n;i++){
int k;
double Min=1e9+7;
for(int j=1;j<=n;j++){
if(!flag[j]&&dis[j]<Min){
Min=dis[j];
k=j;
}
}
flag[k]=1;
for(int j=1;j<=n;j++){
if(!flag[j]&&dis[j]>max(Distance(j,k),Min)) //dijkstra变形
dis[j]=max(Distance(j,k),Min);
}
}
}
int main(){
int t=1;
while(scanf("%d",&n)!=EOF){
if(n==0)break;
for(int i=1;i<=n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
dijkstra(1);
printf("Scenario #%d\n",t++);
printf("Frog Distance = %.3f\n\n",sqrt(dis[2]));
}
return 0;
}
POJ1797 Heavy Transportation
与上面同理,dijkstra的变形
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
int n,flag[1005],m;
int a[1005][1005],dis[1005];
void dijkstra(int x){
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++){
dis[i]=a[1][i];
}
for(int i=1;i<=n;i++){
int k;
int Max=0;
for(int j=1;j<=n;j++){
if(!flag[j]&&dis[j]>Max){
Max=dis[j];
k=j;
}
}
flag[k]=1;
for(int j=1;j<=n;j++){
if(!flag[j]&&dis[j]<min(a[k][j],Max))
dis[j]=min(a[k][j],Max);
}
}
}
int main(){
int t=1,x;
while(scanf("%d",&x)!=EOF){
while(x--){
scanf("%d%d",&n,&m);
int x,y,z;
memset(a,0,sizeof(a));
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
a[x][y]=a[y][x]=z;
}
dijkstra(1);
printf("Scenario #%d:\n",t++);
printf("%d\n\n",dis[n]);
}
}
return 0;
}
POJ3268 Silver Cow Party
题意:有n块地,m条单行路,每个地上都有一个牛,这个牛要去编号位X的地,然后还要回来,求最大的时间。
这个题也是dijkstra算法,先求每个地方到X的最短时间,然后存起来,再把开始存的mp数组转置,这样再求的“每个地方到X的最短时间”就相当于X到每个地方的最短时间了,再把两个时间加起来。
下面展示一些 内联代码片
。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
using namespace std;
int mp[1005][1005],n,m,x;
int dis[1005],dis2[1005],vis[1005];
void change(){
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
swap(mp[i][j],mp[j][i]);
}
}
}
void dijkstra(int x){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
dis[i]=mp[i][x];
}
vis[x]=1;dis[x]=0;
for(int i=0;i<n;i++){
int Min=1e9+7,k;
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]<Min){//printf("hh\n");
Min=dis[j];
k=j;
}
}
vis[k]=1;
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]>mp[j][k]+Min){
dis[j]=mp[j][k]+Min;
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&x);
int xx,yy,zz;
memset(mp,1e9+7,sizeof(mp));
for(int i=0;i<m;i++){
scanf("%d%d%d",&xx,&yy,&zz);
mp[xx][yy]=zz;
}
dijkstra(x); //求每个牛到X的最短时间
for(int i=1;i<=n;i++){
dis2[i]=dis[i];
}//记录到另一个数组里,因为后面的dijkstra会把这个数组覆盖
change(); //转置
dijkstra(x); //求X到每个地方的最短时间
int Max=0;
for(int i=1;i<=n;i++){
Max=max(Max,dis[i]+dis2[i]);
}
printf("%d\n",Max);
return 0;
}
floyd算法(任意两点多额最短距离)
三重循环,很慢(要注意三重循环的顺序)
for(int k=1;k<=n;k++){ //中转节点
for(int i=1;i<=n;i++){ //第一个点
for(int j=1;j<=n;j++){ //第二个点
if(mp[i][j]<mp[i][k]+mp[k][j])
mp[i][j]=mp[i][k]+mp[k][j];
}
}
}
POJ3660 Cow Contest
题意:给出一些两个牛之间比赛的结果,问能确定多少牛的排名
就是看有多少牛跟所有牛都有关系,用floyd算法,条件是a[i][k]=1&&a[k][j]=1 得到a[i][j]=1 (i 和 j 有关系)
下面展示一些 内联代码片
。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m,x,y;
int a[105][105]={0};
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
a[x][y]=1;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][k]&&a[k][j])
a[i][j]=1;
}
}
}
int ans=0;
for(int i=1;i<=n;i++){//找第i个是不是与其他牛都有关系
int flag=0;
for(int j=1;j<=n;j++){
if(j!=i&&a[i][j]==0&&a[j][i]==0){
flag=1;break;
}
}
if(flag==0)ans++;
}
printf("%d\n",ans);
return 0;
}
POJ2240 Arbitrage
题意:有n种货币,m种汇率,求有没有办法可以通过不同货币的兑换来赚钱。
floyd+map,条件是a[i][j]<a[i][k]*a[k][j], 得到a[i][j]=a[i][k]*a[k][j] (换更大的汇率),最后看每种货币自己和自己的汇率是否大于1(用map存不同货币的名称的代号)
下面展示一些 内联代码片
。
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
using namespace std;
double a[35][35]={0.0};
int main(){
int n,m,t=1;
string s;
map<string,int> mp;
while(scanf("%d",&n)!=EOF){
if(!n)break;
for(int i=0;i<n;i++){ //给每种货币一个代号
cin>>s;
mp[s]=i;
}
for(int i=0;i<n;i++){ //初始化
for(int j=0;j<n;j++){
if(i==j)a[i][j]=1.0;
}
}
scanf("%d",&m);
string s1,s2;
double x;
for(int i=0;i<m;i++){
cin>>s1>>x>>s2;
a[mp[s1]][mp[s2]]=x;
}
for(int k=0;k<n;k++){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(a[i][j]<a[i][k]*a[k][j]){
a[i][j]=a[i][k]*a[k][j];
}
}
}
}
int flag=0;
for(int i=0;i<n;i++){ //找有没有自己跟自己兑换>1的
if(a[i][i]>1){flag=1;break;}
}
printf("Case %d: ",t++);
if(flag)printf("Yes\n");
else printf("No\n");
}
}