题目链接:http://poj.org/problem?id=3767
题意:(引自:http://www.cnblogs.com/mycapple/archive/2012/08/21/2649607.html)
由于战争,一个商人想从城市1,回到自己的家城市2,其中城市1始终是由领导1,城市2始终由领导2,其中,商人回家的路中只能有一条路上连接由两个领导领导的城市,还有就是给出的路上双向的,也就是如果城市1能到城市2,那么城市2也同样能到城市1,这是关键。
由于这个题中从1类城市走到2类城市后就不能再回去,只能穿过一次,所以先存为双向路,后面再根据不同类型的城市,把双向路变为单向路
N个城市,城市编号为1,2,3,……N
M条路,路为双向路。 提供每条路的长度及端点城市编号,每两个城市之间直接连通的路最多一条。
这N个城市分为两个集合,部分属于集合1,部分属于集合2,提供每个城市所属的集合,现要求从城市1出发去城市2,要求途径的路中最多出现一条其两端城市不属于同一个集合 的路,求出符合该条件下的从城市1到城市2的最短路,若不存在符合条件的路,输出-1
注:数据中城市1必定属于集合1,城市2必定属于集合2
题解:
(1)由于城市1与城市2所属的集合固定,故在路径中必定有一条而且只能有一条路从属于集合 1的城市出发进入城市2,而定不会出现从集合2走向集合1的城市。
如此,M条路中凡是连接属于不同集合的城市的路为单向路,只能从集合1中的城市走向集合2, 在此基础上用Dijkstra算法求最短路即可。
(2)其实还可以在每个阵营中做一次dijkstra,然后枚举连接两个阵营的边,做和取最小。
代码:
(1)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAX=600+5; const int INF=0x3f3f3f3f; int g[MAX][MAX]; int dis[MAX]; int cmp[MAX]; int vis[MAX]; int n,m; void dijkstra() { for(int i=1;i<=n;i++) { dis[i]=g[1][i]; vis[i]=0; } vis[1]=1; for(int i=1;i<=n;i++) { int p=-1,mmin=INF; for(int j=1;j<=n;j++) { if(!vis[j]&&dis[j]<mmin) { p=j; mmin=dis[j]; } } if(p!=-1) { vis[p]=1; for(int j=1;j<=n;j++) { if(!vis[j]) { dis[j]=min(dis[j],dis[p]+g[p][j]); } } } } } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d",&n)&&n) { scanf("%d",&m); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) g[i][j]=i==j?0:INF; } while(m--) { int a,b,t; scanf("%d%d%d",&a,&b,&t); g[a][b]=g[b][a]=t; } for(int i=1;i<=n;i++) { scanf("%d",&cmp[i]); } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(cmp[i]==1&&cmp[j]==2) g[j][i]=INF; } } /* for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { printf("%d ",g[i][j]); } printf("\n"); }*/ /* for(int i=1;i<=n;i++) printf("%d ",dis1[i]); printf("\n"); for(int i=1;i<=n;i++) printf("%d ",dis2[i]); printf("\n");*/ dijkstra(); if(dis[2]==INF) printf("-1\n"); else printf("%d\n",dis[2]); } return 0; }(2)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAX=600+5; //const int INF=0x3f3f3f3f; const int INF=10000000; int g[MAX][MAX]; int dis1[MAX],dis2[MAX]; int cmp[MAX]; int n,m; void dijkstra(int st,int *dis) { int vis[MAX]; for(int i=1;i<=n;i++) { dis[i]=g[st][i]; vis[i]=0; } vis[st]=1; for(int i=1;i<=n;i++) { if(cmp[i]==st) { int p=-1,mmin=INF; for(int j=1;j<=n;j++) { if(cmp[j]==st&&!vis[j]&&dis[j]<mmin) { p=j; mmin=dis[j]; } } if(p!=-1) { vis[p]=1; for(int j=1;j<=n;j++) { if(cmp[j]==st&&!vis[j]) { dis[j]=min(dis[j],dis[p]+g[p][j]); } } } } } } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d",&n)&&n) { scanf("%d",&m); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) g[i][j]=i==j?0:INF; } while(m--) { int a,b,t; scanf("%d%d%d",&a,&b,&t); g[a][b]=g[b][a]=t; } for(int i=1;i<=n;i++) { scanf("%d",&cmp[i]); } /* for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { printf("%d ",g[i][j]); } printf("\n"); }*/ dijkstra(1,dis1); dijkstra(2,dis2); /* for(int i=1;i<=n;i++) printf("%d ",dis1[i]); printf("\n"); for(int i=1;i<=n;i++) printf("%d ",dis2[i]); printf("\n");*/ int mmin=INF; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(cmp[i]==1&&cmp[j]==2) { mmin=min(mmin,dis1[i]+g[i][j]+dis2[j]); } } } if(mmin>=INF)//不是== printf("-1\n"); else printf("%d\n",mmin); } return 0; }