二分图

二分图

没有网络流不能做的二分图!(不是)

二分图最大匹配模板

最小点权覆盖也是如此。

#include<bits/stdc++.h>
using namespace std;

const int N=505;
int n,m,e,ans,bp[N],cnt[N];
bool d[N][N],vis[N];

bool dfs(int x)
{
	for(int i=1;i<=m;++i)
	if(d[x][i]&&!vis[i])
	{
		vis[i]=1;
		if(!bp[i]||dfs(bp[i])){bp[i]=x;return 1;}
	}
	return 0;
}

int main()
{
	scanf("%d %d %d",&n,&m,&e);
	for(int i=1,x,y;i<=e;++i) scanf("%d %d",&x,&y),d[x][y]=1;
	
	for(int i=1;i<=n;++i)
	if(dfs(i))
	{
		memset(vis,0,sizeof(vis));
		ans++;
	}	
	
	printf("%d",ans);
}

只有DFS部分比较重要,这样写只是因为数据很小而已,数据大了还是链表储存。

acwing 棋盘覆盖

给定一个N行N列的棋盘,已知某些格子禁止放置。

求最多能往棋盘上放多少块的长度为2、宽度为1的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。

输入格式

第一行包含两个整数N和t,其中t为禁止放置的格子的数量。

接下来t行每行包含两个整数x和y,表示位于第x行第y列的格子禁止放置,行列数从1开始。

输出格式

输出一个整数,表示结果。

数据范围

1≤N≤1001≤N≤100

输出样例:

8 0

输出样例:

32
#include<bits/stdc++.h>
using namespace std;
#define id(x,y) (x-1)*n+y
const int N=1e4+5;
int n,m,ans,bp[N],v[N][10];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
bool mp[N][N],vis[N];

bool dfs(int x)
{
	for(int i=1;i<=v[x][0];++i)
	if(!vis[v[x][i]])
	{
		vis[v[x][i]]=1;
		if(bp[v[x][i]]==0||dfs(bp[v[x][i]]))
		{
			bp[v[x][i]]=x;
			return 1;
		}
	}
	return 0;
}
int main()
{
	scanf("%d %d",&n,&m);
	
	for(int i=1,x,y;i<=m;++i) scanf("%d %d",&x,&y),mp[x][y]=1;
	
	for(int i=1;i<=n;++i)
	for(int j=1;j<=n;++j)
	if(!mp[i][j]&&((i+j)&1))
	{
		int x=id(i,j);
		for(int k=0;k<4;++k)
		{
			int xx=i+dx[k],yy=j+dy[k];
			if(xx&&xx<=n&&yy&&yy<=n&&!mp[xx][yy]) v[x][++v[x][0]]=id(xx,yy);
		}
	}
	
	int S=id(n,n);
	for(int i=1;i<=S;++i)
	if(v[i][0]&&dfs(i))
	{
		memset(vis,0,sizeof(vis));
		ans++;
	}
	
	printf("%d",ans);
}

acwing 机器任务

给出一些边,边连接u,v两个点,求最小点权覆盖。

#include<bits/stdc++.h>
using namespace std;

const int N=105,M=1005;
int n,m,k,bp[N];
int te,v[M],pre[M],tail[N];
bool vis[N];

inline void add(int x,int y)
{
	++te;v[te]=y;pre[te]=tail[x];tail[x]=te;
}

bool dfs(int x)
{
	for(int i=tail[x];i;i=pre[i])
	if(!vis[v[i]])
	{
		vis[v[i]]=1;
		if(bp[v[i]]==0||dfs(bp[v[i]])) 
		{
			bp[v[i]]=x;
			return 1;
		}
	}
	return 0;
}
int main()
{
	while(~scanf("%d",&n)&&n)
	{
		memset(tail,0,sizeof(tail));
		memset(bp,0,sizeof(bp));
		te=0;
		
		scanf("%d %d",&m,&k);
		for(int i=1,a,x,y;i<=k;++i)
		{
			scanf("%d %d %d",&a,&x,&y);
			if(!x||!y) continue;
			add(x,y);
		}
		
		int ans=0;
		for(int i=1;i<=n;++i)
		if(tail[i])
		{
			memset(vis,0,sizeof(vis));
			if(dfs(i)) ans++;
		}
		
		printf("%d\n",ans);
	}
}

acwing 泥泞的区域

在一块 N*M 的网格状地面上,有一些格子是泥泞的,其他格子是干净的。

现在需要用一些宽度为1、长度任意的木板把泥地盖住,同时不能盖住干净的地面。

每块木板必须覆盖若干个完整的格子,木板可以重叠。

求最少需要多少木板。

即对于每个格子,要么选一个横着覆盖它的板子,要么选一个竖着覆盖它的板子,或者两个都选。即二分图中的边。

建边的时候以向右或是向下遇到的第一个干净格子,为了保证一定有干净格子,最右和最下增加一排干净格子,这样连续的几个格子连到的点就是一样的。

acwing 马的放置

和网络流车的放置一样,网络流专题里有证明最后弄出来是一个二分染色图,对于白色格子向四周可以连边的格子连边,求最小点权覆盖。

acwing 捉迷藏

Vani和cl2在一片树林里捉迷藏。

这片树林里有N座房子,M条有向道路,组成了一张有向无环图。

树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。

如果从房子A沿着路走下去能够到达B,那么在A和B里的人是能够相互望见的。

现在cl2要在这N座房子里选择K座作为藏身点,同时Vani也专挑cl2作为藏身点的房子进去寻找,为了避免被Vani看见,cl2要求这K个藏身点的任意两个之间都没有路径相连

为了让Vani更难找到自己,cl2想知道最多能选出多少个藏身点。

输入格式

输入数据的第一行是两个整数N和M。

接下来M行,每行两个整数 x,y,表示一条从 x 到 y 的有向道路。

输出格式

输出一个整数,表示最多能选取的藏身点个数。

数据范围

N≤200,M≤30000

挑选一些点使这些点互不相连,就是指最大点权独立集,网络流专题内有详细讲解。因为N很小,所以可以直接Floyed求点与点是否相连,然后重新建图,相连的点就建边,不相连就不建,然后求最小点权覆盖,用总点数减去最小点权覆盖就是最大点权独立集。

posted @ 2020-10-23 20:33  林生。  阅读(81)  评论(0)    收藏  举报