HDU5521 最短路,添加点

Inspire:将思路理清,将难点抛离出来,将问题抽象化,再思考解决方法。

Analysis:最短路问题,难在建图。如果用邻接矩阵,边太多了,而点的个数我们可以接受,仔细读题发现,给出的集合内的任意的两个点的距离都是一定的,于是每个集合构造一个新的点作为中转站,集合内的点都连接两条线到该点,进来再出去,为了防止/2得到浮点数,所以进边和出边的权值都是t,最后结果/2。然后spfa搜两遍最短路,每个点的最大值作为两人在该点约会所需的时间,所有点中最小值即答案。

Note:需要初始化的变量(如pre[]、dis[])以及标志标量(如visted[])等,都要及时清零(改变),并注意清零的位置放在哪。

//哪些变量需要初始化,需要在哪个位置初始化,莫忘!仔细检查!
#include <iostream>
#include <stdio.h>
#include <queue>
#include <set>
#include <vector>
#include <math.h>
#include <algorithm>
#include <string.h>
using namespace std;

typedef long long ll;
const int maxn=(1e6+10);
const ll MAXN=1e17;
ll dis1[maxn];
ll dis2[maxn];
int n,m;
int cnt=0;
int cur_set;
int pre[maxn];
int visted[maxn];
struct Edge{
    int u,v,w;
    int next;
    Edge(int u,int v,int w){
        this->u=u;this->v=v;this->w=w;
    }
    Edge(){}
}edge[maxn<<1];
void Add(int u,int v,int w){
    edge[cnt]=Edge(u,v,w);
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
}
void Spfa(int x,ll dis[]){
    queue<int> que;
    que.push(x);
    visted[x]=1;
    for(int i=1;i<=cur_set;i++){
        dis[i]=MAXN;
        visted[i]=0;
    }
    dis[x]=0;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        visted[u]=0;
        int v,w;
        for(int i=pre[u];~i;i=edge[i].next){
            v=edge[i].v;
            w=edge[i].w;
            if(dis[v]>dis[u]+w){
               dis[v]=dis[u]+w;
               if(!visted[v]){
                    que.push(v);
                    visted[v]=1;//不要忘啊!!
               }
            }
        }

    }

}
int main()
{
    int tt;
    scanf("%d",&tt);
    int kk=1;
    int t,num,x;
    while(tt--){
        scanf("%d%d",&n,&m);
        cur_set=n;
        cnt=0;

        memset(pre,-1,sizeof(pre));//要放在建图前,要全部初始化而不等cur_set

        for(int i=1;i<=m;i++){
            scanf("%d%d",&t,&num);
            cur_set++;
            for(int j=1;j<=num;j++){
                scanf("%d",&x);
                Add(x,cur_set,t);
                Add(cur_set,x,t);
            }
        }

        //错误位置:
        //for(int i=1;i<=cur_set;i++){
            //pre[i]=-1;
           ///visted[i]=0; visted[i]放在这初始化就错了,因为两个dis[]
       // }


        Spfa(1,dis1);
        Spfa(n,dis2);

        vector<int> vec;
        //set<int> sset;set存储速度好像不如用vector然后最后sort一下

        ll minn=MAXN;
        for(int i=1;i<=n;i++){
            minn=min(minn,max(dis1[i],dis2[i]));
        }
        for(int i=1;i<=n;i++){
            if(minn==max(dis1[i],dis2[i]))    vec.push_back(i);
                //sset.insert(i);
        }

        if(minn==MAXN){
            cout<<"Case #"<<kk++<<": "<<"Evil John"<<endl;
        }
        else{
            cout<<"Case #"<<kk++<<": "<<minn/2<<endl;
           
           //用set时的输出:
            /*
            set<int>::iterator it=sset.begin();
            cout<<*it;
            it++;
            for(;it!=sset.end();it++){
                cout<<" "<<*it;
            }
            cout<<endl;
            */
            
            
            //另一种比较方便的写法:虽然比cout慢几百ms,但是在时限为几千ms的题来说问题不大
            /*
            sort(vec.begin(),vec.end());
            for(int i=0;i<vec.size();i++){
                printf("%d%c",vec[i],i==vec.size()-1?'\n':' ');
            }
            */
            sort(vec.begin(),vec.end());
            cout<<vec[0];
            for(int i=1;i<vec.size();i++){
                cout<<" "<<vec[i];
            }
            cout<<endl;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值