hdu 4725 (spfa+建图) 明显要求最短路

如果按照自己建图点个数为(N^2) 明显这个复杂度是不行的,过后,可以把每一层分成上个层进入点,和到下层的进入点,只需要把某一个边变成C就可以了,比赛的时候收惨写了2个u 到 v 没写v 到u 开始的时候tle了,然后单调队列优化了下 ,就worng 了 结果wrong了一下午,后面发现有些层没点,但是自己的代码考虑到了,晚上才ac哎,
#include<cstdio>
#include<cstring>
#include<queue>
#include<deque>
#define inf 0x3f3f3f3f
#define M 700000
#define ll int
using namespace std;
struct G{
    ll head[M],en;
    struct E{
        ll u,v,next,cost;
    }e[M<<2];
    void init(){
        memset(head,-1,sizeof(head));en=0;
    }
    void add(ll u,ll v,ll cost){
        e[en].u=u;e[en].v=v;e[en].cost=cost;e[en].next=head[u];head[u]=en++;
    }
}g1;
ll dis[M];
bool vis[M];
ll realx(ll v,ll u,ll cost){
    if(dis[v]>dis[u]+cost){
        dis[v]=dis[u]+cost;
        return 1;
    }
    return 0;
}
deque<ll > q1;
ll spfa(ll sp,ll tp){
    memset(vis,1,sizeof(vis));
    memset(dis,inf,sizeof(dis));
    while(!q1.empty()) q1.pop_front();
    q1.push_back(sp);
    dis[sp]=0;vis[sp]=0;
    while(!q1.empty()){
        ll u=q1.front();q1.pop_front();
        for(ll i=g1.head[u];~i;i=g1.e[i].next){
            ll v=g1.e[i].v;ll cost=g1.e[i].cost;
            if(realx(v,u,cost)){
                if(vis[v]){
                    vis[v]=0;
                    if(!q1.empty()){
                        ll t1=q1.front();
                        if(dis[v]<dis[t1])
                        q1.push_front(v);
                        else q1.push_back(v);
                    }else q1.push_back(v);
                }
            }
        }
        vis[u]=1;
    }
    return dis[tp];
}
bool can_use[M];
int a1[M];
int main(){
    ll n,m,c,cas;
    while(~scanf("%d",&cas)){
        for(ll q=1;q<=cas;q++){
        scanf("%d%d%d",&n,&m,&c);
        g1.init();
        memset(can_use,0,sizeof(can_use));
        for(ll i=1;i<=n;i++){
            ll t1;scanf("%d",&t1);
            a1[i]=t1;
            g1.add(t1+n,i,c); //入边
            g1.add(i,t1+2*n,c);// 出边
            can_use[t1]=1;
        }
        for(int i=1;i<=n;i++){
            int t1=a1[i];
            if(t1==1) continue;
            if(can_use[t1-1]){
                g1.add(t1+2*n-1,i,0); //上层边点
                g1.add(i,t1+n-1,0);   // 上层入边
            }
        }
        for(ll i=0;i<m;i++){
            ll u,v,cost;scanf("%d%d%d",&u,&v,&cost);
            g1.add(u,v,cost);g1.add(v,u,cost);
        }
        ll ans=spfa(1,n);
        printf("Case #%d: ",q);
        if(ans!=dis[M-1])
        printf("%d\n",ans);
        else printf("-1\n");
        }
    }
    return 0;
}
/*
3
3 0 1
1 1 1
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值