[bzoj1059] [ZJOI2007]矩阵游戏

http://www.lydsy.com/JudgeOnline/problem.php?id=1059

我好菜啊,想了好久不知道怎么做。。

然后去黄学长博客看了一眼:   "不管怎么交换,同行的还是同行,同列的还是同列,所以求的是n个不同行列的点"

瞬间就会做了......

二分图匹配,每一行和每一列看作一个点,某行某列如果是1那么它们之间连边。

想着这下不会wa了吧  结果flag秒收,发现边表忘了开两倍....

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define S 0
#define T 401
#define INF 200000000
#define ms(x) memset(x,0,sizeof(x))
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

struct edge{
    int to,next,w;
}e[90005];
int head[T+5];
int n,cnt,ans;
int q[T+5];
queue<int> qu;

inline void INS(int f,int t,int w)
{e[++cnt]=(edge){t,head[f],w};head[f]=cnt;}
inline void ins(int f,int t,int w){INS(f,t,w);INS(t,f,0);}

int dfs(int x,int f)
{
    if(x==T) return f;
    int used=0;
    for(int i=head[x];i;i=e[i].next)
    if(e[i].w&&q[e[i].to]==q[x]+1)
    {
        int w=dfs(e[i].to,min(f-used,e[i].w));
        used+=w;
        e[i].w-=w;
        e[i^1].w+=w;
        if(used==f) return used;
    }
    if(!used) q[x]=-1;
    return used;
}

bool bfs()
{
    for(int i=1;i<=T;i++) q[i]=-1;q[S]=0;
    qu.push(S);
    while(!qu.empty())
    {
        int u=qu.front();qu.pop();
        for(int i=head[u];i;i=e[i].next)
           if(e[i].w&&q[e[i].to]==-1)
               q[e[i].to]=q[u]+1,qu.push(e[i].to);
    }
    return q[T]!=-1;
}

int main()
{
    int qq=read();
    while(qq--)
    {
        cnt=1;ans=0;ms(head);
        n=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if((read())==1)
                    ins(i,j+n,1);
        for(int i=1;i<=n;i++) ins(S,i,1),ins(i+n,T,1);
        while(bfs()) ans+=dfs(S,INF);
        if(ans==n) puts("Yes");
        else puts("No");
    }
    return 0;
}

 

posted @ 2017-02-25 21:04  FallDream  阅读(188)  评论(0编辑  收藏  举报