luoguP2764

点击打开链接

网络流24题,题意是在有向无环图中求最小路径覆盖。

蒟蒻想不出。。看了题解才明白。。


建图思路:

首先,网络上是没有流的。每个节点自成一家。

然后。。考虑一个类似合并的操作:每有一条有向边,就可以考虑是否合并这两个节点,这个可以用网络流调整得出答案。

最后要输出的 答案,就是原来节点数n-合并的次数


具体实现:

对于序号为i的节点,拆成Xi与Yi两个部分

1、由s向所有Xi连一条流量为1的边

2、由所有Yi向t连一条流量为1的边

3、每有一条边(i,j)就从Xi向Yj连一条流量为1的边。若在网络流增广时使用了这条边,就说明两个节点合并。

答案很好统计。。


总结:

1、在做dinic的时候,又犯了一些错误,导致Wa了两次

2、还是不容易想到网络流的建图思路。。。

hhhhhhhhhhhhhhhhhhhhhhh

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cctype>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
#include<sstream>
#include<cstdlib>
#include<ctime>
#include<list>
#include<deque>
#include<bitset>
#include<fstream>
#define ld double
#define ull unsigned long long
#define ll long long
#define pii pair<int,int >
#define iiii pair<int,pii >
#define mp make_pair
#define INF 1000000000
#define MOD 1000000007
#define rep(i,x) for(int (i)=0;(i)<(x);(i)++)
inline int getint()
{
	int x=0,p=1;char c=getchar();
	while (c<=32)c=getchar();
	if(c==45)p=-p,c=getchar();
	while (c>32)x=x*10+c-48,c=getchar();
	return x*p;
}
using namespace std;
//
const int maxn=500+5;
const int s=400;
const int t=401;
struct E
{
	int to,val,rev;
};
int n,m,res,dis[maxn],iter[maxn],ord[maxn],pre[maxn];
vector<E>G[maxn];
vector<int>ans[maxn];
queue<int>qu;
//
inline void faddedge(int x,int y)
{
	G[x].emplace_back((E){y,1,(int)G[y].size()});
	G[y].emplace_back((E){x,0,(int)G[x].size()-1});
}
bool bfs()
{
	memset(dis,-1,sizeof(dis));
	qu.push(s);dis[s]=0;
	while (!qu.empty())
	{
		int u=qu.front();
		qu.pop();
		rep(i,G[u].size())
		{
			E e=G[u][i];
			if(e.val>0&&dis[e.to]<0)
			{
				dis[e.to]=dis[u]+1;
				qu.push(e.to);
			}
		}
	}
	return (dis[t]>0);
}
int dfs(int v,int val)
{
	if(v==t)return val;
	while (iter[v]<G[v].size())
	{
		E &e=G[v][iter[v]];
		if(dis[e.to]>dis[v]&&e.val>0)
		{
			int ans=dfs(e.to,min(val,e.val));
			if(ans>0)
			{
				e.val-=ans;
				G[e.to][e.rev].val+=ans;
				return ans;
			}
		}
		iter[v]++;
	}
	return 0;
}
void dinic()
{
	while (bfs())
	{
		memset(iter,0,sizeof(iter));
		int f;
		while (f=dfs(s,INF));
	}
}
void sufsolve()
{
	memset(pre,-1,sizeof(pre));
	memset(ord,-1,sizeof(ord));
	rep(i,n)rep(j,G[i].size())
	{
		E e=G[i][j];
		if(e.val==0&&e.to>=n&&e.to<2*n)pre[e.to-n]=i;
	}
	int cnt=0;
	while (1)
	{
		rep(i,n)
		{
			if(pre[i]==-1)
			{
				ans[res++].emplace_back(i);
				ord[i]=res-1;
				cnt++;
			}
			else if(ord[pre[i]]>=0)
			{
				ans[ord[pre[i]]].emplace_back(i);
				ord[i]=ord[pre[i]];
				cnt++;
			}
		}
		if(cnt==n)break;
	}
	rep(i,res)
	{
		rep(j,ans[i].size())printf("%d ",ans[i][j]+1);
		putchar('\n');
	}
	printf("%d\n",res);
}
int main()
{
	n=getint();m=getint();
	rep(i,n)
	{
		faddedge(s,i);
		faddedge(i+n,t);
	}
	rep(i,m)
	{
		int x=getint()-1,y=getint()-1;
		faddedge(x,y+n);
	}
	dinic();
	sufsolve();
	return 0;
}

阅读更多

没有更多推荐了,返回首页