题目链接:http://lightoj.com/volume_showproblem.php?problem=1002
题目描述:将一条路上最大的边称为这条路的花费。选取花费最少的一条路。
解题思路:
改进后的Dijkstra,精髓在于这句话:
ans[i]=min(ans[i],max(ans[st],cost[st][i]));
因为ans[i]是ans[st]所能连接到的下一个节点,如果cost[i][j]比ans[st]大的话,就可以替代ans[st]而成为ans[i]的值了。又因为我们要选取若干个ans[i]中最小的,所以前面加min
通过这道题应该反思一下Dijkstra,我觉得Dijkstra蕴含两种基本思想:
①贪心。每次都选出距离起点最短的点A,难道还能有比这更短的路径到A么?这应该算是贪心
②DP。或者说是递推,即上一个节点的答案通过一定规律传递给下一个节点,对下一个节点产生无后效性的作用。就像这道题,当前点和上一点是有关系的
比赛时候一片头晕,看来功底不够,后来慢慢想出来的 = =
唉,差得远啊~
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int INF=9999999;
int N;
int cost[550][550],ans[550],vis[550];
void reset()
{
int i,j;
for(i=0;i<550;i++)
for(j=0;j<550;j++)
cost[i][j]=INF;
for(i=0;i<550;i++)
cost[i][i]=0;
}
void dijkstra(int st)
{
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
int i,j,p;
for(i=0;i<N;i++)
ans[i]=cost[st][i];
vis[st]=1;
while(1)
{
int minans=INF;
for(i=0;i<N;i++)
{
if(ans[i]<minans&&!vis[i])
{
minans=ans[i];
p=i;
}
}
if(minans==INF)break;
vis[p]=1;
st=p;
for(i=0;i<N;i++)
{
ans[i]=min(ans[i],max(ans[st],cost[st][i]));
}
}
}
int main()
{
//freopen("A_input.txt","r",stdin);
int T,M,u,v,w,i,st,cc=1;
cin>>T;
while(T--)
{
reset();
cin>>N>>M;
while(M--)
{
cin>>u>>v>>w;
cost[u][v]=cost[v][u]=min(cost[u][v],w);
}
cin>>st;
dijkstra(st);
cout<<"Case "<<cc<<":"<<endl;
cc++;
for(i=0;i<N;i++)
{
if(ans[i]==INF)
cout<<"Impossible"<<endl;
else
cout<<ans[i]<<endl;
}
}
return 0;
}
AC截图: