Loading

P1129 [ZJOI2007]矩阵游戏

P1129 [ZJOI2007]矩阵游戏

这题想到思路就很好做了。

设输入的矩阵为s。如果 \(s_{i,j}=1\) 那么连边 (i,j).然后跑最大流,看看是否等于n。s向行连边,列向t连边。 \(maxflow=n\) 说明有解,否则无解。

仔细想想,好像是有点道理……

考虑说明正确性.原矩阵相当于一个打乱的图,最大流不管乱不乱都可以跑出它的最优解。

引用一句dalao的话:交换行的本质就是交换向s连的边,交换列同理,所以不影响匹配数

#include<bits/stdc++.h>
using namespace std;
#define rint register int
const int N=405;
const int inf=1<<30;
int cur[N],head[N],depth[N];
int maxflow,n,s,t,T,num_edge=1;
bool inq[N];
struct edge{
	int to,next,val;
}e[N*N*2];
void add(int from,int to,int val)
{
	++num_edge;
	e[num_edge].val=val;
	e[num_edge].to=to;
	e[num_edge].next=head[from];
	head[from]=num_edge;
}
bool bfs()
{
	for(rint i=1;i<=t;i++)
		cur[i]=head[i],inq[i]=false,depth[i]=0x3f3f3f3f;
	queue<int>q;
	depth[s]=0;
	inq[s]=true;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		inq[u]=false;
		for(int i=head[u];i;i=e[i].next)
		{
			int to=e[i].to;
			if(e[i].val&&depth[to]>depth[u]+1)
			{
				depth[to]=depth[u]+1;
				if(!inq[to])
				{
					inq[to]=true;
					q.push(to);
				}
			}
		}
	}
	return depth[t]!=0x3f3f3f3f;
}
int dfs(int u,int flow)
{
	if(u==t)
	{
		maxflow+=flow;
		return flow; 
	}
	int used=0,rlow=0;
	for(int i=cur[u];i;i=e[i].next)
	{
		int to=e[i].to;
		cur[u]=i;
		if(e[i].val&&depth[to]==depth[u]+1)
		{
			if(rlow=dfs(to,min(flow-used,e[i].val)))
			{
				used+=rlow;
				e[i].val-=rlow;
				e[i^1].val+=flow;
				if(used==flow)break;
			}
		}
	}
	return used;
}
void dinic()
{
	while(bfs())dfs(s,inf);
}
void clear()
{
	memset(head,0,sizeof(head));
	num_edge=1;
	maxflow=0;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		clear();
		scanf("%d",&n);
		s=n+n+1;t=n+n+2;
		for(int i=1;i<=n;++i)
			add(s,i,1),add(i,s,0);
		for(int i=1;i<=n;++i)
			add(i+n,t,1),add(t,i+n,0);
		for(int i=1;i<=n;++i)
		{
			for(int j=1,x;j<=n;++j)
			{
				scanf("%d",&x);
				if(x==1)add(i,j+n,1),add(j+n,i,0);
			}
		}
		dinic();
		if(maxflow==n)puts("Yes");
		else puts("No");
	}
	return 0;
}
posted @ 2020-02-24 22:14  zzctommy  阅读(157)  评论(0编辑  收藏  举报