少し上に最近の肝臓ネットワークフロー
実際に、私はちょうど水のブログのタイトルをしたいしたくありません
完了する前にブログナンセンス
\(羅\ 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);
}