최근 간 네트워크는 상단에 작은 흐름
사실, 난 그냥 물 블로그 제목을 원하는 싶지 않아
완료되기 전에 블로그 넌센스
으로 \ (루오 \ 번지는 \) 24 개 질문 중 하나 고전적인 네트워크 종양은 물론의 블로그 쓰기
전송
결국 제목에 무슨 말을?
존재하는 DAG.도 임의의 경로를 선택할 이제 각 경로가 선택되어, 경로에 포함 +1 점의 수, 모든 지점이 포함되어있는 점 번만 포함되도록. 선택된 경로의 수는 커버리지 경로이다. 최소 경로 범위는 경로의 최소 수있다.
다음은 간단한 밤나무
1 덮는 최단 경로가 분명
레드 핫 패스되고
당신이주는 경우에 우리가 수행하는 방법의 매우 복잡한 견해는 무엇입니까?
이 경로는 가장 큰 것은 N-1 음주 운전의 쌍 커버? (폭력 등의 선출 나무 같은 것들, 그것은 N-1 가장자리가)
우리가 경로의 범위가 작아 고려
> B와 b - -이 있지만 우리가 선출하는 경우> C면 다음, 그들은 하나 개의 경로로 결합 할 수 있도록 응답 -1
물론이 기간 B에 주목있을 경우 -> D면은 후 -> 단 B b로부터 -> C 및 B - 선택된> d는 병합
후 최소 경로 범위가 통합 측을 계속하는 것입니다, 그것은 더 이상까지 합병에 통합되었습니다
분명히 우리는이 일을하고 네트워크 흐름을 문의해야(그렇지 않으면 네트워크가 종양 24 문제라는 방법)
네트워크 흐름은 이분 그래프 매칭을 생각 맞물 리도록 할 수 있습니다
우리는이 작업 점을 분할 한 기대하는
분할 소수점 연산은 게이샤입니다
도트가 두 지점 및 아웃 포인트로 분할 될 상기 관통 점만이 침투뿐만 아니라도 지적하지 않는다.
가장자리와 종점 지점에도 동안은, 측면의 관점에서 그 시점을 의미
포인트 및 아웃점 종료 후 발견 된 그래프 그
이 마법의 작동, 우리는 한면을 병합 할 때마다, 경기를 선출한다. 우리는 많은면을 병합 할, 이분 그래프의 최대 매칭되는 많은 일치로 선출
여기에 있습니다 헝가리이 좋은 물건을 (또한 부수적으로 경로를 기록)를 사용할 수 있습니다 이분 그래프 최대 매칭 알고리즘을 추구하지만, 네트워크 네트워크 종양 의 세계 사회가 , 우리는 네트워크 흐름 밖으로의 사용을 고려한다.
도 위의 내장 가야 (가 스트리밍 네트워크를 얻을 수와 동일), 다음 단계는 암의 경로를 기록하는 것입니다
실수 + N,이 예비 처리 될 수있다 YS (MAP) 어레이, YS의 포인트 개수도 시점의 구성되어 고려 [I]는 i 포인트 실수 (대 즉, 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);
}