题意:
有向无环图中,需要多少条简单路可以覆盖整个图。
建模:
构造二分图。把原图的每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图的边(i, i),连接(Xi, Yj),值为1,然后把二分图最大匹配模型转化为网络留模型,求最大流。
分析:
对于一个路径覆盖,有如下性质:
1、每个顶点属于且只属于一个路径。
2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。
所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。
注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <memory.h>

using namespace std;

const int MAXN = 100;
const int MAXM = MAXN*MAXN;
const int INF = 0x7FFFFFF;


typedef struct edge
{
edge *next, *op;
int t,c;
}edge;

edge ES[MAXM], *V[MAXN], *P[MAXN], *Stae[MAXN];
int level[MAXN], Stap[MAXN];
int M, N, S, T, EC, Ans, Maxflow;

ifstream fin("path.in");
ofstream fout("path.out");


inline void addedge(int a, int b, int c)
{
ES[++EC].next=V[a], V[a]=ES+EC, V[a]->t=b, V[a]->c=c;
ES[++EC].next=V[b], V[b]=ES+EC, V[b]->t=a, V[b]->c=0;
V[a]->op=V[b], V[b]->op=V[a];
}


bool Dinic_Level()
{
int head,tail,i,j;
Stap[head=tail=0]=S;
memset(level,-1,sizeof(level));
level[S]=0;

while (head<=tail)
{
i=Stap[head++];

for (edge *e=V[i];e;e=e->next)
{
j=e->t;

if (e->c && level[j]==-1)
{
level[j] = level[i]+1;
if (j==T)
return true;
Stap[++tail] = j;
}
}
}
return false;
}

int match[MAXN+MAXN];

void Dinic_Augment()
{
int i,j,delta,Stop;

memcpy(P, V, sizeof(edge*)*MAXN);

Stap[Stop=1]=S;

while (Stop)
{
i=Stap[Stop];

if (i!=T)
{
for (;P[i];P[i]=P[i]->next)
if (P[i]->c && level[i] + 1 == level[j=P[i]->t])
break;

if (P[i])
{
Stap[++Stop] = j;
Stae[Stop] = P[i];
}else
Stop--,level[i]=-1;

}else
{
delta = INF;
for (i=Stop;i>=2;i--)
if (Stae[i]->c < delta)
delta = Stae[i]->c;
Maxflow += delta;

for (i=Stop;i>=2;i--)
{
Stae[i]->c -= delta;
Stae[i]->op->c += delta;
if (Stae[i]->c==0)
Stop = i-1;
}
match[Stae[2]->t] = Stae[3]->t;
}
}
}


void Dinic()
{
while (Dinic_Level())
Dinic_Augment();
}


void input()
{
int a,b,i;
fin>>N>>M;
S=0, T=N+N+1;

for(i=1; i<=N; ++i)
{
addedge(S, 2*i-1,1);
addedge(2*i, T, 1);
}


for(i=1; i<=M; ++i)
{
fin>>a>>b;
addedge(2*a-1, 2*b, INF);
}
}

bool visited[MAXN];

void dfs(int k)
{
fout<<(k+1)/2<<" ";

if(match[k]&&!visited[k])
{
visited[k]=true;
dfs(match[k]-1);
}
}


void output()
{
int c = N+N;

for(int i=1; i<c; i+=2)
{

if(match[i]&&!visited[i])
{
dfs(i);
fout<<endl;
}
}
fout<<N-Maxflow<<endl;
}


int main()
{
input();
Dinic();
output();
return 0;
}
posted on 2011-03-05 23:29
小阮 阅读(1822)
评论(0) 编辑 收藏 引用 所属分类:
数据结构和算法