码迷,mamicode.com
首页 > 其他好文 > 详细

学了一年文化课后变成 白痴退役夕阳红选手的 陈年老题信心%你赛 B题

时间:2018-03-29 21:12:03      阅读:116      评论:0      收藏:0      [点我收藏+]

标签:ons   多个   标记   scanf   turn   printf   algorithm   i++   family   

唉。没什么话说。

首先我这个傻子考场上都知道,先把mmin求出来,再用mmin那些边的节点去spfa延伸找其他点。

然而都是口胡。

看一下细节。男神先把全部的边都减去mmin,这样一来spfa的时候不用每次都增加,减少编程复杂度,然后spfa的时候也是一个我没有想到的操作,就是他非常心安理得的第二维只开了2

一个朴素的想法是f[i][j]表示走到点i,有j条边要使用后面的边权的最短路。f[i][j]可以转移到f[k][0]或f[k][j+1]。然而这样边数是O(n3)O(n3)的,spfa不资磁。。 

但是考虑做最短路的目的是找到一个标记点,走到很多个中间点显然不是什么好方案。具体来说,从i走j条边到k,只是为了使用最后一条边权(s,k),那为什么不直接i->s->k呢?所以f[i][j]中的j只需要取0,1。 

ORZ

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const LL inf(1LL<<60);

int n;LL mmin;
LL mp[2100][2100];
struct list_
{
    int x,w;
}list[4100];bool v[2100][2];
LL d[2100][2];

void spfa()
{
    memset(d,63,sizeof(d));
    memset(v,false,sizeof(v));
    int head=1,tail=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(mp[i][j]==0&&i!=j)
            {
                d[i][0]=0;
                v[i][0]=true;
                list[tail].x=i;
                list[tail].w=0;
                tail++;
                break;
            }
    while(head!=tail)
    {
        int x=list[head].x,w=list[head].w;
        for(int y=1;y<=n;y++)
        {
            if(x==y)continue;
            LL dis=d[x][w]+(w+1)*mp[x][y];
            if(d[y][0]>dis)
            {
                d[y][0]=dis;
                if(v[y][0]==false)
                {
                    v[y][0]=true;
                    list[tail].x=y;
                    list[tail].w=0;
                    tail++;if(tail==4050)tail=1;
                }
            }
            if(w==0)
            {
                dis=d[x][w];
                if(d[y][1]>d[x][w])
                {
                    d[y][1]=d[x][w];
                    if(v[y][1]==false)
                    {
                        v[y][1]=true;
                        list[tail].x=y;
                        list[tail].w=1;
                        tail++;if(tail==4050)tail=1;
                    }
                }
            }
        }
        v[x][w]=false;
        head++;if(head==4050)head=1;
    }
}
int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    scanf("%d",&n);mmin=inf;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            scanf("%lld",&mp[i][j]);
            mp[j][i]=mp[i][j];
            mmin=min(mmin,mp[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j)
                mp[i][j]-=mmin;
    spfa();
    for(int i=1;i<=n;i++)printf("%lld\n",d[i][0]+(n-1)*mmin);
    return 0;
}

 

学了一年文化课后变成 白痴退役夕阳红选手的 陈年老题信心%你赛 B题

标签:ons   多个   标记   scanf   turn   printf   algorithm   i++   family   

原文地址:https://www.cnblogs.com/AKCqhzdy/p/8671950.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!