又一点多了,昨天好开心,因为小孩子生日。。希望她可以永远快快乐乐的~You are my greatest motivation,really love you.
第一次用spfa,关于spfa具体可看http://hi.baidu.com/qw4365/blog/item/115b211a8ffd14b94aedbcbf.html
/* zoj_1857 最短路 终于是过了,感觉收获良多~ 题意:有n个点,每个点至少一个house,有些点有一个或多个fire station(fs)。求在哪个点增加一个fs,能使 所有house到离它最近的那个fs的最大距离最小。 Process: 1.第一反应就是floyd了,然后犹犹豫豫的写了。 2.居然MLE,改成滚动数组,zoj上TLE了,poj上wa 3.然后发现mark木有初始化(见代码2),改完后zoj上TLE,poj上AC(2000多ms) 4.然后看到网上好像很多人spfa过的,果断学了下spfa,很快写完用spfa实现的代码。 poj上AC,可是居然是4000多ms,zoj肯定TLE啦。。 5.开始查找自己的spfa到底存在什么问题,发现我的spfa里面有句 if( dist[i]>dist[temp]+map[temp][i] ) 明显右边是要越界的,速度改成if( map[temp][i]!=inf && dist[i]>dist[temp]+map[temp][i] ),提交后 poj过了(1000多ms),zoj也终于过了,开心~ 收获: 1.sscanf的用法 2.spfa 3.改成spfa+邻接表 效率应该是更高的,没有试了。 */ //代码1:spfa+邻接矩阵(1000多ms) #include <iostream> #include <cstdio> #include <string.h> #include <limits.h> #include <queue> #define inf 99999999 #define N 510 using namespace std; int flag[N]; int ori[N],dist[N]; int map[N][N]; void inint() { int i,j; for( i=0;i<N;i++ ) { for( j=0;j<N;j++ ) { if( i==j ) map[i][j]=0; else map[i][j]=inf; } ori[i]=INT_MAX; } memset( flag,0,sizeof(flag) ); } void spfa( int sta,int n ) { queue <int>q; int hash[N],temp,i; memset( hash,0,sizeof(hash) ); for( i=0;i<=n;i++ ) dist[i]=INT_MAX; dist[sta]=0; q.push( sta ); hash[sta]=1; while( !q.empty() ) { temp=q.front(); q.pop(); hash[temp]=0; for( i=1;i<=n;i++ ) { if( map[temp][i]!=inf && dist[i]>dist[temp]+map[temp][i] ) //一开始没写map[temp][i]!=inf,TLE了 { dist[i]=dist[temp]+map[temp][i]; if( hash[i]==0 ) hash[i]=1 , q.push(i); } } } } int findmax( int id,int n ) { int temp,i,maxi; maxi=-1; spfa( id,n ); for( i=1;i<=n;i++ ) if( !flag[i] ) { temp=ori[i]; if( dist[i]<temp ) temp=dist[i]; if( maxi<temp ) maxi=temp; } return maxi; } int main() { //freopen( "AAA_a.txt","r",stdin ); int n,m,temp,i,j; int a,b,v,mini,mark; char str[100]; while( scanf("%d%d",&n,&m)!=EOF ) { inint(); for( i=0;i<n;i++ ) scanf( "%d",&temp ) , flag[temp]=1 ; getchar(); while( gets(str) && strlen(str) ) { sscanf( str,"%d%d%d",&a,&b,&v ); map[a][b]=map[b][a]=v; } for( i=1;i<=m;i++ ) if( flag[i] ) { spfa( i,m ); for( j=1;j<=m;j++ ) if( ori[j]>dist[j] ) ori[j]=dist[j]; } mini=INT_MAX; mark=1; for( i=1;i<=m;i++ ) if( !flag[i] ) { if( mini>( temp=findmax( i,m ) ) ) mini=temp , mark=i ; } printf( "%d\n",mark ); } return 0; }
//代码2:floyd+滚动数组(2000多ms) //poj AC,zoj TLE #include <iostream> #include <cstdio> #include <string.h> #include <limits.h> #define inf 99999999 #define N 510 using namespace std; bool flag[N]; int map[N][N]; int dist[N][N][2]; int ori[N]; void inint() { int i,j; for( i=0;i<N;i++ ) { for( j=0;j<N;j++ ) { if( i==j ) map[i][j]=0; else map[i][j]=inf; } ori[i]=INT_MAX; } memset( flag,0,sizeof(flag) ); } void floyd( int n ) { int i,j,k; for( i=0;i<=n;i++ ) for( j=0;j<=n;j++ ) dist[i][j][0]=map[i][j]; for( k=1;k<=n;k++ ) { for( i=1;i<=n;i++ ) for( j=1;j<=n;j++ ) { dist[i][j][1]=dist[i][j][0]; if( dist[i][j][1]>dist[i][k][0]+dist[k][j][0] ) dist[i][j][1]=dist[i][k][0]+dist[k][j][0]; } for( i=1;i<=n;i++ ) for( j=1;j<=n;j++ ) dist[i][j][0]=dist[i][j][1]; } } int findmax( int id,int n ) { int temp,i,maxi; maxi=-1; for( i=1;i<=n;i++ ) if( !flag[i] ) { temp=ori[i]; if( dist[i][id][0]<temp ) temp=dist[i][id][0]; if( maxi<temp ) maxi=temp; } return maxi; } int main() { //freopen( "AAA_a.txt","r",stdin ); int n,m,temp,i,j; int a,b,v,mini,mark; char str[100]; while( scanf("%d%d",&n,&m)!=EOF ) { inint(); for( i=0;i<n;i++ ) scanf( "%d",&temp ) , flag[temp]=1 ; getchar(); while( gets(str) && strlen(str) ) { sscanf( str,"%d%d%d",&a,&b,&v ); map[a][b]=map[b][a]=v; } floyd(m); for( i=1;i<=m;i++ ) { if( !flag[i] ) { for( j=1;j<=m;j++ ) if( flag[j] && ori[i]>dist[i][j][0] ) ori[i]=dist[i][j][0]; } else ori[i]=0; } mini=INT_MAX; mark=1; //这个初始化必须,否则如果每个点都有fire station就错了 for( i=1;i<=m;i++ ) if( !flag[i] ) { if( mini>( temp=findmax( i,m ) ) || mini==INT_MAX ) mini=temp , mark=i ; } printf( "%d\n",mark ); } return 0; }