描述
国庆期间正是旅游和游玩的高峰期。
小Hi和小Ho的学习小组为了研究课题,决定趁此机会派出若干个调查团去沿途查看一下H市内各个景点的游客情况。
H市一共有N个旅游景点(编号1..N),由M条单向游览路线连接。在一个景点游览完后,可以顺着游览线路前往下一个景点。
为了避免游客重复游览同一个景点,游览线路保证是没有环路的。
每一个调查团可以从任意一个景点出发,沿着计划好的游览线路依次调查,到达终点后再返回。每个景点只会有一个调查团经过,不会重复调查。
举个例子:
上图中一共派出了3个调查团:
1. 蓝色:调查景点;2
2. 橙色:调查景点;1->3->4->6
3. 绿色:调查景点;5->7
当然对于这个图还有其他的规划方式,但是最少也需要3个调查团。
由于小组内的人数有限,所以大家希望调查团的数量尽可能少,同时也要将所有的景点都进行调查。
当然,如何规划调查团线路的任务落到了小Hi和小Ho的头上。
输入
第1行:2个整数N,M。1≤N≤500,0≤M≤20,000。
第2..M+1行:2个数字u,v,表示一条有向边(u,v)。保证不会出现重复的边,且不存在环。
输出
第1行:1个整数,表示最少需要的调查团数量。
思路:这个题目的话是典型的最小路径覆盖的题目,其实之前在那个看二分图的时候就已经看过了,就当是在练练吧,
代码1:
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<iostream>
#define INF 1e9
using namespace std;
const int maxn=500*2+10;
struct Edge
{
Edge(){}
Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
int from,to,cap,flow;
};
struct Dinic
{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n,int s,int t)
{
this->n=n,this->s=s,this->t=t;
for(int i=1;i<=n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap)
{
edges.push_back( Edge(from,to,cap,0) );
edges.push_back( Edge(to,from,0,0) );
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int> Q;//用来保存节点编号的
Q.push(s);
d[s]=0;
vis[s]=true;
while(!Q.empty())
{
int x=Q.front(); Q.pop();
for(int i=0; i<G[x].size(); i++)
{
Edge& e=edges[G[x][i]];
if(!vis[e.to] && e.cap>e.flow)
{
vis[e.to]=true;
d[e.to] = d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x,int a)
{
if(x==t || a==0)return a;
int flow=0,f;//flow用来记录从x到t的最小残量
for(int& i=cur[x]; i<G[x].size(); i++)
{
Edge& e=edges[G[x][i]];
if(d[x]+1==d[e.to] && (f=DFS( e.to,min(a,e.cap-e.flow) ) )>0 )
{
e.flow +=f;
edges[G[x][i]^1].flow -=f;
flow += f;
a -= f;
if(a==0) break;
}
}
return flow;
}
int Maxflow()
{
int flow=0;
while(BFS())
{
memset(cur,0,sizeof(cur));
flow += DFS(s,INF);
}
return flow;
}
}dinic;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int S=0,T=n*2+1;
dinic.init(2*n,S,T);
for(int i=1;i<=n;i++)
dinic.AddEdge(0,i,1);
for(int i=1;i<=n;i++)
dinic.AddEdge(n+i,T,1);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
dinic.AddEdge(x,y+n,1);
}
printf("%d\n",n-dinic.Maxflow());
}
代码2:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=500+10;
int F[maxn],vis[maxn],pre[maxn];
int findset(int x)
{
if(F[x]==-1)return x;
return F[x]=findset(F[x]);
}
vector<int >G[maxn];
bool DFS(int u)
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(vis[v]) continue;
vis[v]=1;
if(pre[v]==0||DFS(pre[v]))
{
pre[v]=u;
return true;
}
}
return false;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(DFS(i)) ans++;
}
printf("%d\n",n-ans);
}