ACM队内训练第六周的专题是图论中最短路径问题,今晚终于把五道题目都AC了,下面依次总结一下并奉上代码。
题目列表
对应poj题目 |
---|
poj1125 Stockbroker Grapevine |
poj3615 Cow Hurdles |
poj1847 Tram |
poj1502 MPI Maelstrom |
poj1860 Currency Exchange |
NO.1 poj1125 Stockbroker Grapevine
题目给定一个有向图,求解最短路径,要求输出作为源的顶点坐标以及该顶点到达某个顶点的最大权值。数据量100,使用Floyd算法,复杂度为n^3。无特殊处理。
/*最短路径算法-Floyd算法*/
#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define maxn 0x3f3f3f3f
struct Graph{ //邻接矩阵表示法
int arcs[105][105];
}g;
struct ShortPath{
int a[105][105];
}path;
void floyd(int n){
for(int i=0 ; i<n ; i++) //初始化
for(int j=0 ; j<n ; j++)
path.a[i][j] = g.arcs[i][j];
for(int k=0 ; k<n ; k++)
for(int i=0 ; i<n ; i++)
for(int j=0 ; j<n ; j++){
if(path.a[i][k]>=maxn || path.a[k][j]>=maxn)
continue;
if(path.a[i][j] > (path.a[i][k] + path.a[k][j]))
path.a[i][j] = path.a[i][k] + path.a[k][j];
}
}
int main()
{
//freopen("in.txt","r",stdin);
int n;
while(cin>>n && n!=0){
int m,j;
memset(g.arcs,maxn,sizeof(g.arcs));
for(int i=0 ; i<n ; i++)
g.arcs[i][i]=0;
for(int i=0 ; i<n ; i++){
cin>>m;
while(m--){
cin>>j;
cin>>g.arcs[i][j-1];
}
}
floyd(n);
int shortpath=maxn,pathlen,point=0;
for(int i=0 ; i<n ; i++){
bool flag=true;
pathlen=0;
for(int j=0 ; j<n ; j++){
if(path.a[i][j]>=maxn){
flag=false;
break;
}
pathlen += path.a[i][j];
}
if(!flag)
continue;
if(shortpath>pathlen){
shortpath=pathlen;
point=i;
}
}
if(shortpath>=maxn)
cout<<"disjoint"<<endl;
else{
cout<<point+1<<" ";
sort(path.a[point],path.a[point]+n);
cout<<path.a[point][n-1]<<endl;
}
}
return 0;
}
NO.2 poj3615 Cow Hurdles
题目要求最短路径中任意两点的最大距离,采用Floyd算法,直接把二维数组用作邻接矩阵,WA了两次,原因是输入时需注意从一根柱子跳到另一根柱子是不可逆的,也就是说a[x][y]!=a[y][x]。
#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define maxn 0x3f3f3f3f
int a[305][305];
void floyd(int n){
for(int k=1 ; k<=n ; k++)
for(int i=1 ; i<=n ; i++)
for(int j=1 ; j<=n ; j++)
a[i][j] = min(a[i][j],max(a[i][k],a[k][j]));
}
int main(){
int n,m,t;
while(scanf("%d%d%d",&n,&m,&t)!=EOF){
int x,y,z;
// memset(a,maxn,sizeof(a));
for(int i=1 ; i<=n ; i++)
for(int j=1 ; j<=n ; j++)
a[i][j]=maxn;
while(m--){
//cin>>x>>y;
scanf("%d%d%d",&x,&y,&z);
a[x][y]=z;
//a[y][x]=a[x][y];错误,需留意
}
floyd(n);
while(t--){
scanf("%d%d",&x,&y);
if(a[x][y]>=maxn)
printf("-1\n");
else
printf("%d\n",a[x][y]);
}
}
return 0;
}
NO.3 poj1847 Tram
题目意思是说有n个点,从A点到其他点,若可达且是该行输入的第一个点则权值为0,若可达且不是第一个点则权值为1,否则不可达。由于数据量不大,使用Floyd算法求解。
#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define maxn 0x3f3f3f3f
int point[105][105];
int n,a,b;
void floyd(){
for(int q=1 ; q<=n ; q++)
for(int i=1 ; i<=n ; i++)
for(int j=1 ; j<=n ; j++){
if(point[i][j]>(point[i][q]+point[q][j]))
point[i][j] = point[i][q]+point[q][j];
}
}
int main(){
while(~scanf("%d%d%d",&n,&a,&b)){
int m,k;
for(int i=1 ; i<=n ; i++){ //初始化
for(int j=1 ; j<=n ; j++){
if(i==j)
point[i][j]=0;
else
point[i][j]=maxn;
}
}
for(int i=1 ; i<=n ; i++){
scanf("%d",&m);
for(int j=0 ; j<m ; j++){
scanf("%d",&k);
if(j==0)
point[i][k]=0;
else
point[i][k]=1;
}
}
floyd();
if(point[a][b]>=maxn)
cout<<-1<<endl;
else
cout<<point[a][b]<<endl;
}
return 0;
}
NO.4 poj1502 MPI Maelstrom
无向图求最短路径,无特殊要求,直接使用Dijkstra算法求解,复杂度为n^2。
/*Dijkstra算法-最短路*/
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define max 0x3f3f3f3f
struct Graph{ //邻接矩阵表示法
int arcs[105][105];
}g;
int dist[105]; //储存最短路径
void init(Graph pg,int dist[],int n){
dist[0] = 0;
pg.arcs[0][0] = 1; //若对角线元素为1,则表示该顶点已被使用
for(int i=1 ; i<n ; i++)
dist[i] = pg.arcs[0][i];
}
void dijkstra(Graph g,int dist[],int n){
int mv,minw;
init(g,dist,n); //初始化
for(int i=1 ; i<n ; i++){
minw=max;
mv=0;
for(int j=1 ; j<n ; j++) //选出距离v0最近的顶点
if(g.arcs[j][j]==0 && dist[j]<minw){
mv=j;
minw=dist[j];
}
if(mv == 0) break; //v0与vi不连通,结束
g.arcs[mv][mv] = 1;
for(int j=1 ; j<n ; j++){
if(g.arcs[j][j]==0 && dist[j] >dist[mv]+g.arcs[mv][j]){
dist[j] = dist[mv]+g.arcs[mv][j];
}
}
}
}
int main(){
int n;
while(cin>>n){
memset(g.arcs,0,sizeof(g.arcs));
string input;
for(int i=1 ; i<n ; i++){
for(int j=0 ; j<i ; j++){
cin>>input;
if(input=="x"){
g.arcs[i][j]=max;
g.arcs[j][i]=max;
}else{
g.arcs[i][j]=atoi(input.c_str());
g.arcs[j][i]=atoi(input.c_str());
}
}
}
dijkstra(g,dist,n);
sort(dist,dist+n);
cout<<dist[n-1]<<endl;
}
return 0;
}
NO.5 poj1860 Currency Exchange
Bellman_Ford算法求解有向带权图是否存在正负环。数组开小导致RE,遍历的时候注意起点,输入的变量较多,顺序容易搞错。
#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
struct Edge{
int u,v;
double rate,cost;
};
Edge edge[1005];
double dist[5005];
double ss;
int start,count1;
bool Bellman_Ford(int n){
memset(dist,0,sizeof(dist));
dist[start]=ss;
bool flag;
for(int i=1 ; i<n ; i++){
flag=false;
for(int j=0 ; j<count1 ; j++)
if(dist[edge[j].v] < (dist[edge[j].u]-edge[j].cost)*edge[j].rate){
dist[edge[j].v] = (dist[edge[j].u]-edge[j].cost)*edge[j].rate;
flag = true;
}
if(!flag)
break;
}
for(int j=0 ; j<count1 ; j++)
if(dist[edge[j].v] < (dist[edge[j].u]-edge[j].cost)*edge[j].rate)
return true;
return false;
}
int main(){
int n,m;
while(cin>>n>>m>>start>>ss){
count1=0;
int uu,vv;
double p1,p2,p3,p4;
while(m--){
cin>>uu>>vv>>p1>>p2>>p3>>p4;
edge[count1].u=uu;
edge[count1].v=vv;
edge[count1].rate=p1;
edge[count1].cost=p2;
count1++;
edge[count1].u=vv;
edge[count1].v=uu;
edge[count1].rate=p3;
edge[count1].cost=p4;
count1++;
}
if(Bellman_Ford(n))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
结语
图论的题目接触不多,一开始写的代码有些赘余,后来发现后慢慢改正一些。感受最深的一处是:数据量不大的情况下,直接用二维数组表示图的邻接矩阵比较方便。以后做ACM题要有快速建模的意识!