BZOJ1059: 矩阵游戏 题解

我们考虑什么样的棋盘是符合题意的,我们会发现同一行和同一列如果有多个黑格子,那么他们之中最多有一个能成为最后的对角线
进一步发现,我们如果能在棋盘上找到n个黑格子,使得他们的行号,列号两两不同,那么就能拼出对角线,这个条件等价于每个行和列都被一枚棋子匹配了一次
于是想到我们对每个行建一个点,对每一个列建一个点,形成一个二分图,对于在a[i][j]的黑格子,就在行的i和列的j之间连一条边,最后跑一个二分图最大匹配,如果是n说明有解
这个思路还是挺棒的

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=100003;
const LL LINF=2e16;
const int INF=1e9;
const int magic=348;
const double eps=1e-10;

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int head[100048],nxt[200048],to[200048],f[200048],tot=1;
inline void addedge(int s,int t,int cap)
{
    to[++tot]=t;nxt[tot]=head[s];head[s]=tot;f[tot]=cap;
    to[++tot]=s;nxt[tot]=head[t];head[t]=tot;f[tot]=0;
}

int n;
int a[1048][1048];

inline void Clear()
{
    tot=1;
    memset(head,0,sizeof(head));
}

int depth[100048];queue<int> q;
inline bool bfs()
{
    int i,x,y;
    for (i=0;i<=n+n+1;i++) depth[i]=-1;
    depth[0]=0;q.push(0);
    while (!q.empty())
    {
        x=q.front();q.pop();
        for (i=head[x];i;i=nxt[i])
        {
            y=to[i];
            if (depth[y]==-1 && f[i])
            {
                depth[y]=depth[x]+1;
                q.push(y);
            }
        }
    }
    if (depth[n+n+1]==-1) return false; else return true;
}

inline int dfs(int x,int maxf)
{
    if (x==n+n+1) return maxf;
    int i,y,minf,now,ans=0;
    for (i=head[x];i;i=nxt[i])
    {
        y=to[i];
        if (depth[y]==depth[x]+1 && f[i])
        {
            minf=min(maxf-ans,f[i]);
            now=dfs(y,minf);
            f[i]-=now;f[i^1]+=now;ans+=now;
        }
        if (ans>=maxf) return ans;
    }
    if (ans==0) depth[x]=0;
    return ans;
}

int main ()
{
    int i,j,ca;ca=getint();
    while (ca--)
    {
        n=getint();Clear();
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
            {
                a[i][j]=getint();
                if (a[i][j]) addedge(i,n+j,1);
            }
        for (i=1;i<=n;i++) addedge(0,i,1);
        for (i=1;i<=n;i++) addedge(n+i,n+n+1,1);
        int ans=0;
        while (bfs()) ans+=dfs(0,INF);
        if (ans>=n) printf("Yes\n"); else printf("No\n");
    }
    return 0;
}

你可能感兴趣的:(二分图匹配)