题目链接: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;
}