練習への総合的グラフ理論

グラフ理論のテストは基本的に、SPAF何うん、krushkalうん、うんtranj、必要なテンプレートを訓練するために考えている、と残りはの思考を実践することです...

A:最短:

変更後、図最短最大となるよう、前記対象は、その増加側を必要とします。

増加は0の単位で元を変更した後、ほとんどの短絡など、意味がないのため、明らかに、我々は、元中央アフリカの最短辺を増やすことはできません。

その後、我々は唯一の庭の図は、ラインの最短辺であることを検討してください。小規模データは、エッジに住むために、あなたは最短経路を再実行することができます。

細部へのこだわり、ここでの最短経路の記録は次のとおりです。

#include <ビット/ STDC ++ H> 
 使用して 名前空間STDを、
const  int型 MAXN = 5100 ;
長い N、M、リンク[MAXN]、TOT、ZHI [MAXN]、VIS [MAXN]、DIS [MAXN]、ID [MAXN]、O、MAXX、mazx。
構造体
{ 
    長い 長いY、次に、V。
}。
扁[MAXN * 2 ]。
インライン長い ロング)(読み取り
{ 
    長い  X = 0、FF = 1 チャー CH = GETCHAR()。
    しばらく(!isdigit(CH))
    { 
        場合(CH == ' - ')FF = - 1 
        CH = GETCHAR()。
    } 
    一方(isdigit(CH))
    { 
        X =(X << 1)+(X << 3)+(CH ^ 48 )。
        CH = GETCHAR()。
    } 
    戻りのx *のFF。
} 
インラインボイドSPAF()
{ 
    キュー < INT > Q。
    memset(DIS、127はsizeof (DIS))。
    DIS [ 1 ] = 0; VIS [ 1 ] = 1 ; q.push(1 )。
    一方、(!q.empty())
    { 
        int型のx = q.front(); q.pop(); VIS [X] = 0 ;
        以下のためにint型 ; I; iは=リンクが[X] iは= [I] .next)
        { 
            int型、Yは= .Y [i]は、
            もし(DIS [Y]> DIS [X] + [I] .V)
            { 
                DIS [Y] = DIS [X] + [I] .V; ZHI [Y] =のX。
                もし(VIS [Y]!)q.push(Y)、VIS [Y] = 1 
            } 
        } 
    } 
} 
インラインボイドspaf1()
{ 
    キュー < INT > Q。
    memset(DIS、127はsizeof (DIS))。
    memsetの(VIS、0はsizeof (VIS))。
    DISは、[ 1 ] = 0 ; VIS [ 1 ] = 1 ; q.push(1 )。
    一方、(!q.empty())
    { 
        int型のx = q.front(); VIS [X] = 0 ; q.pop()。
        int型 ; I iが= I =リンク[X]を[I] .next)
        { 
            int型 = yと[I] .Y。
            もし(ID [X] && ID [Y] && DIS [Y]> DIS [X] + [I] .V * 2 
            { 
                DIS [Y] = DIS [X] + [I]・V * 2 もし(VIS [Y]!)q.push(Y)、VIS [Y] = 1 
            } 
            そう であれば(>(!ID [X] ||!ID [Y])&& DIS [Y] DIS [X] + [I] .V)
            { 
                DIS [Y] = DIS [X] + [I] .V。
                もし(VIS [Y]!)q.push(Y)、VIS [Y] = 1 
            } 
        } 
    } 
} 
インラインボイドは(追加INTを、Xint型の Y、INT V)
{ 
    [ ++ TOT] .V = V。
    【TOT] .Y = Y。
    【TOT] .next = リンク[X]。
    リンク[X] = TOT。
} 
int型のmain()
{ 
//     freopenは( "1.in"、 "R"、STDIN)。
    N =読み取る(); M = 読み取ります()。
    以下のためにint型 I = 1 ; I <= M; iは++ 
    { 
        int型のx =リード()、yは読み取ら=()、V = 読み取ります(); 
        (X、Y、V)を追加し、(Y、X、V)を加えます。
    } 
    SPAF(); MAXX = DIS [N]。
    O =N;
    一方、(!= 1 
    { 
        ID [T] = 1 ; ID = [ZHI []の] 1 
        spaf1(); mazx = MAX(mazx、DIS [N])。
        ID [t]は = 0、ID [ZHI []の] = 0 ;  = ZHIあります[]。
    } 
    Coutの << mazx-MAXX << ENDL。
    リターン 0 ; 
}

次の質問:

つまり、牛は牧草地のベールを持つことが許さおいしい値の前提の下で、最短経路を実行しない、その後、家に帰る:質問は突然、私たちが質問のヘアカットの意味、質問を読んで、多くのことを改善しました。

我々は、私は[i]とZの大きさ、短いで[X] + DIS2 [I] -dis1、XはIを指す距離DIS2ベールを表し、我々はDIS1を比較する必要があり、エンドポイントまでの距離を表すDIS1を設定しますもしDIS1 [X] + DIS2 [I] -dis1 [I] <= Zであれば条件を満たしています。

既然如此,那我们看一下哪些是定值(并且好求),显然dis1[x]与dis1[i]我们可以从终点跑一边spaf求出,而dis2[i]就需要枚举每个x求出不同的值,这就是暴力!既然dis1[x]与dis1[i]好求,那我们模仿参变量分离一样,将不等式换一种形式,dis1[x]+dis2[i]-z<=dis1[i],这样右边的变量就是一个定值了。我们剩下的任务就是找到一个草垛使得dis1[x]+dis2[i]-z最小,看到这里,我们终于闻到了最短l路的气息,因为最短路不就是要跑一个最短距离吗?可到这还不行,我们继续想,怎样使得跑的一个路径是dis1[x]+dis2[i]-z呢?dis2[i]还能想到,是某个草捆到一个点的距离,那dis1[x]-z怎么办呢?没有办法,那就自己造呀!这就是这个题的精妙之处,我们建一个超级汇点n+1,使得n+1与每一个草捆都连上一个单向边,

边权就为dis1[x]-z这样从超级汇点跑到一个点的距离就为dis1[x]-z+dis2[i],而且还是最小的,巧妙的解决了这个问题。从超级汇点跑一个spaf之后就简单了,一个一个枚举比较与dis1[i]的大小即可,也没什么细节,实现起来很简单,也就是难想了点。其实启示还是很多的,比如分析题目需要的条件与排除冗杂信息,找到最优的解决方案,此题中的找到最小的dis1[x]+dis2[i]-z就是如此。还有如果实在没有办法依据题中的实现,那就自己创造!超级汇点就是干这个用的。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=100100;
int link[51000],tot,n,m,k,dis[51000],vis[51000],c[51000],id[51000];
struct bian
{
    int y,v,next;
};
bian a[maxn*2];
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-') ff=-1;
        ch=getchar(); 
    } 
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar(); 
    } 
    return x*ff;
}
inline void add(int x,int y,int v)
{
    a[++tot].y=y;
    a[tot].v=v;
    a[tot].next=link[x];
    link[x]=tot; 
} 
inline void spaf(int s)
{
    queue<int>q;q.push(s);
    memset(dis,127,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[s]=0;vis[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();vis[x]=0;
        for(int i=link[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(dis[y]>dis[x]+a[i].v)  
            {
                dis[y]=dis[x]+a[i].v;
                if(!vis[y]) vis[y]=1,q.push(y); 
            }
        } 
    } 
} 
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();k=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read(),v=read();
        add(x,y,v);add(y,x,v);
    } 
    spaf(n);
    for(int i=1;i<=n;i++) c[i]=dis[i];
    for(int i=1;i<=k;i++)
    {
        int x=read(),z=read();
        add(n+1,x,c[x]-z);
    }
    spaf(n+1);
    for(int i=1;i<n;i++)
    {
        if(dis[i]<=c[i]) cout<<1<<endl;
        else             cout<<0<<endl;
    }
     return 0;
}

...

おすすめ

転載: www.cnblogs.com/gcfer/p/11270792.html