最短路径
Aizu - 0189 Convenient Location
弗洛伊德模板题
#include<iostream>
#include<algorithm>
using namespace std;
const int maxx=100;
#define INF 65535
int n;
int m;
int d[maxx][maxx];
void floyd()
{
for (int k = 0; k <= m; k++)
{
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= m; j++)
{
d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
}
}
}
}
int main()
{
while (cin>>n&&n)
{
for (int i = 0; i < maxx; i++)
{
for (int j = 0; j < maxx; j++)
{
d[i][j]=INF;
}
}
m=0;
for (int i = 0; i < n; i++)
{
int x,y,w;
cin>>x>>y>>w;
m=max(m,max(x,y));
d[x][y]=d[y][x]=w;
}
for (int i = 0; i <= m; i++)
{
d[i][i]=0;
}
floyd();
int ans=INF;
int pos=0;
for (int i = 0; i <= m; i++)
{
int sum=0;
for (int j = 0; j <= m; j++)
{
sum+=d[i][j];
}
if(sum<ans)
{
ans=sum;
pos=i;
}
}
cout<<pos<<' '<<ans<<endl;
}
return 0;
}
POJ - 2139 Six Degrees of Cowvin Bacon
同样是一道弗洛伊德模板题
#include<iostream>
#include<algorithm>
using namespace std;
const int maxx=10000+1;
#define INF 65535
int d[310][310];
int a[maxx];
int n,m;
void Floyd()
{
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
d[i][j]=min(d[i][j],(d[i][k]+d[k][j]));
}
}
}
}
int main()
{
cin>>n>>m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
d[i][j]=INF;
if(i==j) d[i][j]=0;
}
}
for (int i = 0; i < m; i++)
{
int x;
cin>>x;
for (int j = 0; j < x; j++)
{
cin>>a[j];
}
for (int i = 0; i < x-1; i++)
{
for (int j = i+1; j < x; j++)
{
int x=a[i],y=a[j];
d[x][y]=d[y][x]=1;
}
}
}
Floyd();
int tot=INF;
for (int i = 1; i <= n; i++)
{
int sum=0;
for (int j = 1; j <= n; j++)
{
sum+=d[i][j];
//cout<<sum<<endl;
}
if (sum<tot) tot=sum;
}
cout<<100*(tot)/(n-1)<<endl;
return 0;
}
POJ - 3259 Wormholes
判断有无负权环,Floyd和Ford都可以使用
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 10001
const int maxx=503;
int d[maxx][maxx];
int n,m,w;
bool Floyd()
{
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if(d[i][j]>d[i][k]+d[k][j])
{
d[i][j]=d[i][k]+d[k][j];
}
}
if(d[i][i]<0) return 1;
//是否存在负权环
}
}
return 0;
}
int main()
{
int p;
cin>>p;
while (p--)
{
cin>>n>>m>>w;
memset(d,INF,sizeof(d));
for (int i = 1; i < n; i++)
{
d[i][i]=0;
}
int x,y,z;
for (int i = 0; i < m; i++)
{
cin>>x>>y>>z;
if(z<d[x][y])
d[x][y]=d[y][x]=z;
}
for (int i = 0; i < w; i++)
{
cin>>x>>y>>z;
d[x][y]=-z;
}
if(Floyd()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
经典的Ford模板,值得记录一下:
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 10001
const int maxx=1e4;
//int d[maxx][maxx];
struct edge
{
int s,e;
int w;
};
edge e[maxx];
int a[maxx];
int n,m,w;
int M;
bool ford()
{
memset(a,0,sizeof(a));
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < M; j++)
{
int u = e[j].s;
int v = e[j].e;
int t = e[j].w;
//cout<<u<<' '<<v<<' '<<t<<endl;
if (a[v] > a[u] + t)
{
a[v] = a[u] + t;
//cout<<a[v];
if(i==n) return 1;
}
}
}
return 0;
}
int main()
{
int p;
cin>>p;
while (p--)
{
cin>>n>>m>>w;
M=0;
int x,y,z;
for (int i = 0; i < m; i++)
{
cin>>x>>y>>z;
e[M].s=x;
e[M].e=y;
e[M++].w=z;
e[M].s=y;
e[M].e=x;
e[M++].w=z;
}
for (int i = 0; i < w; i++)
{
cin>>x>>y>>z;
e[M].s=x;
e[M].e=y;
e[M++].w=-z;
}/*
for (int i = 0; i < M; i++)
{
cout<<e[i].s<<' '<<e[i].e<<' '<<e[i].w<<endl;
}*/
if(ford()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
POJ - 3268 Silver Cow Party
逆向思维,反向建图,两次使用dijkstra,参考了大佬的代码
#include<iostream>
using namespace std;
int n,m,x;
const int maxx=1005;
#define INF 0x3f3f3f3f
int d[maxx][maxx],xd[maxx][maxx];
int a[maxx],xa[maxx];
void dij(int s[maxx][maxx],int q[maxx])
{
bool used[maxx];
memset(used,false,sizeof(used));
memset(q,INF,sizeof(a));
used[x]=0;
for (int i = 1; i <= n; i++)
{
q[i]=s[x][i];
}
for (int i = 1; i <= n; i++)
{
int max=INF;
int v=0;
for (int j = 1; j <= n; j++)
{
if(!used[j]&&q[j]<max)
{
v=j;
max=q[j];
}
}
used[v]=true;
for (int j = 1; j <= n; j++)
{
q[j]=min(q[j],q[v]+s[v][j]);
}
}
}
int main()
{
cin>>n>>m>>x;
memset(d,INF,sizeof(d));
memset(xd,INF,sizeof(xd));
for (int i = 1; i <= n; i++)
{
d[i][i]=0;
xd[i][i]=0;
}
for (int i = 0; i < m; i++)
{
int x,y,z;
cin>>x>>y>>z;
d[x][y]=z;
xd[y][x]=z;
}
dij(d,a);/*
for (int i = 1; i <= n; i++)
{
cout<<a[i]<<' ';
}
cout<<endl;*/
dij(xd,xa);
int min=0;
for (int i = 1; i <= n; i++)
{
min=max(min,a[i]+xa[i]);
}
cout<<min<<endl;
return 0;
}
Aizu - 2249 Road Construction
经典的单源最短路+最小边权,针对图的邻接表利用堆优化后的dijkstra算法
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<functional>
#include<cstdio>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxa=10005;
const int maxx=50005;
struct edge
{
int to,dis,cost;
edge(int _to,int _dis,int _cost):to(_to),dis(_dis),cost(_cost){}
};
typedef pair<int,int> P;
int n,m;
vector<edge> G[maxx];
int d[maxa];
int cost[maxa];//cost存储的是每一步的花费,最终需要累加
void dijkstra(int s)
{
priority_queue<P,vector<P>,greater<P> > que;
memset(d,INF,sizeof(d));
memset(cost,0,sizeof(cost));
d[s]=0;
que.push(P(0,s));
while (!que.empty())
{
P p=que.top();
que.pop();
int v=p.second;//取出顶点编号
if(d[v]<p.first) continue;
for (int i = 0; i < G[v].size(); i++)
{
edge e=G[v][i];
if (d[e.to]>=d[v]+e.dis)
{
if (d[e.to]==d[v]+e.dis)
{
cost[e.to]=min(cost[e.to],e.cost);
//如果距离相等,取较小花费
}
else
{
cost[e.to]=e.cost;
//距离不等,直接赋值
}
d[e.to]=d[v]+e.dis;
que.push(P(d[e.to],e.to));
}
}
}
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF,n+m)
{
for (int i = 1; i <= n; i++)
G[i].clear();
for (int i = 0; i < m; i++)
{
int x,y,z,w;
cin>>x>>y>>z>>w;
G[x].push_back(edge(y,z,w));
G[y].push_back(edge(x,z,w));
}
dijkstra(1);
int sum=0;
for (int i = 1; i <= n; i++)
{
sum+=cost[i];
}
cout<<sum<<endl;
}
return 0;
}
总结
最短路相比较最小生成树都是图论的重要内容,变化更多,四大算法什么时候用以及优化问题还需要不断做题来积累,写题的时候参考了大佬们的代码,从中也学到了很多技巧,刷题干货满满啊。