最短経路問題のフローカバレッジ

少し上に最近の肝臓ネットワークフロー
実際に、私はちょうど水のブログのタイトルをしたいしたくありません
完了する前にブログナンセンス
\(羅\ GU \) 24個の質問の一つ古典的なネットワークの腫瘍はもちろんのブログに書き込むための
転送を


最後にタイトルでは何と言いますか?

DAGは今ある。図は、全ての点がカバーされ、任意の点を一度しか覆われるように、各パスが選択され、覆わ経路上の1点の数を任意のパスを選択しました。選択されたパスの数は、パスカバレッジです。最小パスカバレッジは、パスの最小数です。

ここで簡単栗は、

1を覆う最短パスがことが明らか

赤熱経路であります

あなたは私たちを与える場合に行う方法の非常に複雑なビューのですか?
このパスは、最大のものは、n-1 DUIのペアでカバー?(暴力のような次期のツリー状のものは、それは、n-1のエッジを持っている)
我々はパスカバレッジが小さくなって考える
> BとB - -がある一方で、私たちが選出された場合> C側、その後、彼らそのよう答え-1、一つのパスに結合することができる
D選択> - - > C及びB>のみB bから- > D側次いで、 - 、この時間bに留意すべきである場合、コースマージ
、最小パスカバレッジが統合サイドを継続することで、それはもはやアップ合併に組み込まれています

もちろん、私たちはこの事を取り、ネットワーク・フローを連絡する必要が(そうでない場合は、ネットワークは、腫瘍24件の質問と呼ばれる方法)
ネットワーク・フローは、2部グラフマッチングを考え係合することができる
私たちは、この操作は、ポイントを分割している期待して、その後

スプリットポイントの操作がGeshaです

ドットは、2つの点とアウト点に分割される、侵入の唯一の点は、浸透だけでなく度を指摘されていません。
エッジと終点が点にもあるが、それは、側点からその点を意味します

点とアウト点の完了後に発見される二部グラフ

この魔法のような操作により、我々は片側をマージするたびに、マッチに選出されます。私たちは、できるだけ多くの側面をマージする、二部グラフの最大マッチングである、多くのマッチに選出されます

二部グラフの最大マッチングアルゴリズムを探していることは(もついでにパスを記録)が、ここでハンガリーにこの良いものを使用することができ、ネットワークのネットワーク腫瘍世界のコミュニティ、我々はネットワークフローの使用を検討してください。

図は、上記構築された取得する必要があります(それはストリーミングネットワークを取得することと等価である)、次のステップは、がんのパスを記録することです

図時点の構成を考慮実数+ n個の点の数であり、それはYS(マップ)アレイ、I-ポイントのYS [i]は実数(とき私すなわち、> N、YS [前処理することができますI] =中)

もし残りの量(すなわち、DIS)0片側に、アカウントにネットワークフローの原理を取る、我々はこれを選択したマッチは、それが同じパス内のエッジへの結合点を言うことです。出力パスは、DFSを使用して達成することができるようになっています。DFSはまた、それらの裏面を検討する際に注意してください。

直接接続されているコードの対

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int inf=214748364;
typedef long long ll;
inline int read()
{
    char ch=getchar();
    int x=0;bool f=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return f?-x:x;
}
int n,m,head[409],cnt=1,ans,s,t;
struct E{
    int to,nxt,dis;
}ed[12009];
int dep[409],cur[409];
queue <int> q;
int ys[409];
bool vis[159];
inline void add(int fr,int to,int dis)
{
    cnt++;
    ed[cnt].to=to;
    ed[cnt].dis=dis;
    ed[cnt].nxt=head[fr];
    head[fr]=cnt;
}
inline bool bfs()
{
    for(int i=1;i<=2*n+2;i++)
     dep[i]=0;
    for(int i=1;i<=2*n+2;i++)
     cur[i]=head[i];
    dep[s]=1; 
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int e=head[u];e;e=ed[e].nxt)
        {
            int v=ed[e].to;
            if(ed[e].dis&&!dep[v])
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    return dep[t];
}
int dfs(int now,int in)
{
    if(now==t)return in;
    int out=0;
    for(int e=cur[now];e;e=ed[e].nxt)
    {
        cur[now]=e;
        int v=ed[e].to;
        if(ed[e].dis&&dep[v]==dep[now]+1)
        {
        int ret=dfs(v,min(in,ed[e].dis));
            ed[e].dis-=ret;
            ed[e^1].dis+=ret;
            in-=ret;
            out+=ret;
            if(!in) return out;
        }
    }
    return out;
}
inline void dinic()
{
    int ret;
    while(bfs())
    {
         ret=0;
         while(ret=dfs(s,20000000))ans+=ret;
    }
}
//上面全是网络流
void lj(int u)//路径不是辣鸡 !!!
{
     printf("%d ",u);
    vis[u]=1;//vis记录是否已经输出
    for(int e=head[u];e;e=ed[e].nxt)
    {
        int v=ed[e].to;
        if(v==s||v==t)continue;//这里注意不考虑自己加的超源,超汇
        if(!ed[e].dis&&!vis[ys[v]])
          lj(ys[v]); 
    }
}
int main()
{
    n=read();m=read();s=n*2+1;t=n*2+2;
    for(int i=1;i<=m;i++)
    {
        int fr=read(),to=read();
        add(fr,to+n,1);add(to+n,fr,0);
    }
    for(int i=1;i<=n;i++)
     add(s,i,1),add(i,s,0);
    for(int i=n+1;i<=2*n;i++)
     add(i,t,1),add(t,i,0);
    for(int i=1;i<=n;i++)
     ys[i]=i;
    for(int i=n+1;i<=2*n;i++)
     ys[i]=i-n;
    ys[s]=s;ys[t]=t;
    dinic();
    ans=n-ans;
    for(int i=1;i<=n;i++)//这里就不从超源开始考虑了qwq
    {
        if(!vis[i])
        {
            lj(i);
        printf("\n");
        }
    }
    printf("%d",ans);
}

おすすめ

転載: www.cnblogs.com/lcez56jsy/p/11406174.html
おすすめ