[网络流24题 #3]最小路径覆盖问题
2014-01-23 13:24
190 查看
【问题分析】
有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决。
【建模方法】
构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图中存在的每条边(i,j),在二分图中连接边(Xi,Yj)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。
最小路径覆盖的条数,就是原图顶点数,减去二分图最大匹配数。沿着匹配边查找,就是一个路径上的点,输出所有路径即可。
【建模分析】
对于一个路径覆盖,有如下性质:
1、每个顶点属于且只属于一个路径。
2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。
所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。
注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。
方案很多,这里不输出方案,仅是求出最大流:#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define push(x) push_back(x)
#define MaxN 120
using namespace std;
const int INF=~0U>>2;
int head[MaxN],h[MaxN],v[MaxN];
int n,m,tot,s,t;
struct edge
{
int v,cap,next;
edge(int x,int y,int c):v(y),cap(c),next(head[x])
{
head[x]=tot++;
}
};
vector<edge> a;
inline void AddEdge(int x,int y,int c)
{
a.push(edge(x,y,c));
a.push(edge(y,x,0));
}
int sap(int x,int lim)
{
if(x==t) return lim;
int sum=0,y,flow;
for(int i=head[x];i!=-1;i=a[i].next)
{
y=a[i].v;
if(a[i].cap>0&&h[y]+1==h[x])
{
flow=sap(y,min(a[i].cap,lim-sum));
a[i].cap-=flow;
a[i^1].cap+=flow;
sum+=flow;
if(sum==lim) return sum;
}
}
if(h[s]<=t||!sum)
{
if(!--v[h[x]]) h[s]=t+1;
v[++h[x]]++;
}
return sum;
}
inline int mf()
{
int ans=0;
v[0]=t+1;
while(h[s]<=t)
ans+=sap(s,INF);
return ans;
}
inline void init()
{
int x,y;
memset(head,-1,sizeof(head));
cin>>n>>m;
t=2*n+1;
while(m--)
scanf("%d%d",&x,&y),
AddEdge(x,y+n,1);
for(int i=1;i<=n;i++)
AddEdge(s,i,1),
AddEdge(n+i,t,1);
}
inline void work()
{
int ans=n-mf();
cout<<ans<<endl;
}
int main()
{
init();
work();
return 0;
}
有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决。
【建模方法】
构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图中存在的每条边(i,j),在二分图中连接边(Xi,Yj)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。
最小路径覆盖的条数,就是原图顶点数,减去二分图最大匹配数。沿着匹配边查找,就是一个路径上的点,输出所有路径即可。
【建模分析】
对于一个路径覆盖,有如下性质:
1、每个顶点属于且只属于一个路径。
2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。
所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。
注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。
方案很多,这里不输出方案,仅是求出最大流:#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define push(x) push_back(x)
#define MaxN 120
using namespace std;
const int INF=~0U>>2;
int head[MaxN],h[MaxN],v[MaxN];
int n,m,tot,s,t;
struct edge
{
int v,cap,next;
edge(int x,int y,int c):v(y),cap(c),next(head[x])
{
head[x]=tot++;
}
};
vector<edge> a;
inline void AddEdge(int x,int y,int c)
{
a.push(edge(x,y,c));
a.push(edge(y,x,0));
}
int sap(int x,int lim)
{
if(x==t) return lim;
int sum=0,y,flow;
for(int i=head[x];i!=-1;i=a[i].next)
{
y=a[i].v;
if(a[i].cap>0&&h[y]+1==h[x])
{
flow=sap(y,min(a[i].cap,lim-sum));
a[i].cap-=flow;
a[i^1].cap+=flow;
sum+=flow;
if(sum==lim) return sum;
}
}
if(h[s]<=t||!sum)
{
if(!--v[h[x]]) h[s]=t+1;
v[++h[x]]++;
}
return sum;
}
inline int mf()
{
int ans=0;
v[0]=t+1;
while(h[s]<=t)
ans+=sap(s,INF);
return ans;
}
inline void init()
{
int x,y;
memset(head,-1,sizeof(head));
cin>>n>>m;
t=2*n+1;
while(m--)
scanf("%d%d",&x,&y),
AddEdge(x,y+n,1);
for(int i=1;i<=n;i++)
AddEdge(s,i,1),
AddEdge(n+i,t,1);
}
inline void work()
{
int ans=n-mf();
cout<<ans<<endl;
}
int main()
{
init();
work();
return 0;
}
相关文章推荐
- 线性规划与网络流24题 3最小路径覆盖问题 NEFU 481
- [网络流24题]魔术球问题(简化版) 最小路径覆盖+二分答案 + 很快的最大流
- COGS728. [网络流24题] 最小路径覆盖问题
- [网络流24题]最小路径覆盖问题
- COGS728.[网络流24题]最小路径覆盖问题:网络流
- [网络流24题] 最小路径覆盖问题
- 【二分匹配】 [网络流24题] 最小路径覆盖问题
- 【网络流24题】 No.3 最小路径覆盖问题 (网络流|匈牙利算法 ->最大二分匹配)
- 【网络流24题】No.4 魔术球问题 (二分+最小路径覆盖)
- 【网络流24题】最小路径覆盖问题
- [网络流24题] 最小路径覆盖问题
- [网络流24题] 最小路径覆盖问题
- 线性规划与网络流24——最小路径覆盖问题
- 【网络流24题】魔术球问题 二分答案+最小路径覆盖
- COGS 728. [网络流24题] 最小路径覆盖问题
- 网络流24题 最小路径覆盖问题
- [网络流24题] 03 最小路径覆盖问题(有向无环图最小路径覆盖,网络最大流)
- Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流)
- [网络流24题][CODEVS1904]最小路径覆盖问题(最大流||匈牙利算法)
- 【codevs1904】[网络流24题]最小路径覆盖问题