zoj 1857 || poj 2607

22 篇文章 0 订阅
4 篇文章 0 订阅

又一点多了,昨天好开心,因为小孩子生日。。希望她可以永远快快乐乐的~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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值