hdu1599
题意:n个地方,m条无向路,每条路都要花费一定值,问你一个花费最小的回路并且此回路至少经过两个地点,求此最小花费
刚看到这题,呆呆的我就只能想到在floyd中再多加一个一维数组表示把他当作起点和终点最短路的经过地点是多少个,在进行动态规划时,每个回路都进行累加,最后将经过地点大于等于三个的找最小值,实际上这个思路太过于复杂了,题目中没有要求要搞清楚最小路的路径具体是什么样,所以更好的做法是在每个k中再进行另一次遍历,以这个k作为起点终点并且有i,j作为经过点,那么他求出的最小值一定是经过了两个中间地点的。
#include<iostream>
#include<cstdio>
const int inf=1e6;
int g[1005][1005];//最短路
int G[1005][1005];//只记录初始值,整个题目中是恒定的
int n,m;
using namespace std;
int floyd(){
int k,i,j;
int minn=inf;
for(k=1;k<=n;k++)
{
for(i=1;i<=n;i++)
if(g[i][k]!=inf)
for(j=1;j<=n;j++)
if(g[i][j]<g[i][k]+g[k][j])
g[i][j]=g[i][k]+g[k][j];
for(i=1;i<k;i++)
for(j=1;j<k;j++)
if(minn>g[i][j]+G[i][k]+G[j][k])
minn=g[i][j]+G[i][k]+G[i][k];
}
return minn;
}
int main(){
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
g[i][j]=inf;
while(m--){
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=c;
G[a][b]=G[b][a]=c;
}
for(i=1;i<=n;i++)
g[i][i]=0;
if(floyd()!=inf) cout<<minn<<endl;
else cout<<"impossbile"<<endl;
return 0;
}
HDU3631
题意:还是n个点和m条有向边,q次操作。操作有两种:0:标记x点,如果标记了就输出ERROR! 1: 问从 x 到 y 的最短路(x,y和经过的点都必须被标记过)如果x或y没有被标记过输出“ERROR! ”,如果没有路输出“No such path”。
这题就很适合floyd,因为只有标记的点才需要进行floyd,只要标记一个点,就以这个点作为中间结点来缩短任意两点节点之间的距离,所以每个0操作才对应的一次n^2的遍历
#include<iostream>
#include<cstdio>
const int inf=1e6;
int g[1005][1005];
int mark[1005];
int n,m;
using namespace std;
void init()
{
for(int i=0;i<=n;i++)
{
mark[i]=0;
for(int j=0;j<=n;j++)
g[i][j]=inf;
g[i][i]=0;
}
}
void floyd(int k)
{
for(int i=0;i<n;i++)
if(i!=k)
for(int j=0;j<n;j++)
if(i!=j&&k!=j)
{
if(g[i][j]>g[i][k]+g[k][j])
g[i][j]=g[i][k]+g[k][j];
}
}
int main(){
int i,j;
scanf("%d%d",&n,&m);
init();
while(m--){
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=c;
}
int q;
cin>>q;
while(q--){
int p,a,b,c;
cin>>p;
if(p==0){
cin>>c;
if(mark[c]==1) break;
mark[c]=1;
floyd(a);
}
{
cin>>a>>b;
if(mark[a]==0||mark[b]==0){
cout<<"no crash!"<<endl;
break;
}
if(g[a][b]==inf) cout<<"no crash!"<<endl;
else cout<<g[a][b]<<endl;
}
}
return 0;
}