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;
}
路漫漫其修远兮,吾将上下而求索