zoukankan      html  css  js  c++  java
  • ZJOI2007 矩阵游戏

    传送门

    这道题就是一道不大容易被看出来的二分图匹配……(也可能是我太菜了qaq)

    首先我们看一下,题目要求我们把对角线上都填满。我们把每一行和每一列都抽象成一个点,那么我们只要让每一行和每一列都匹配上就可以。

    先把每行向源点连边,每列向汇点连边,行和列之间,如果g[i][j]是1的话那么就把第i行和第j列之间连边。我们想象一下,交换某两行或者某两列之后,其实连边的情况并没有发生变化,也就是说,最大匹配数无论怎么交换都不会发生改变。

    所以只要在最开始的图上跑一遍dinic求最大匹配即可,如果其等于n说明可以,否则不行。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    const int M = 1005;
    const int N = 100005;
    const int INF = 1e9;
    typedef long long ll;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    struct node
    {
        int next,to,from,v;
    }e[N];
    int t,n,deep[M],source,sink,a,head[M],cur[M],ecnt = -1,maxflow;
    queue <int> q;
    
    void clear()
    {
        memset(head,-1,sizeof(head));
        memset(cur,-1,sizeof(cur));
        ecnt = -1,maxflow = 0;
        source = 0,sink = 401;
        memset(e,0,sizeof(e));
    }
    
    void add(int x,int y,int z)
    {
        e[++ecnt].to = y;
        e[ecnt].from = x;
        e[ecnt].v = z;
        e[ecnt].next = head[x];
        head[x] = ecnt;    
    }
    
    bool bfs(int s,int t)
    {
        memset(deep,-1,sizeof(deep));
        rep(i,0,sink+1) cur[i] = head[i];
        while(!q.empty()) q.pop();
        deep[s] = 0,q.push(s);
        while(!q.empty())
        {
            int k = q.front();q.pop();
            for(int i = head[k];i != -1;i = e[i].next)
            {
                if(deep[e[i].to] == -1 && e[i].v)
                deep[e[i].to] = deep[k] + 1,q.push(e[i].to);
            }
        }
        if(deep[t] == -1) return 0;
        else return 1;
    }
    
    int dfs(int s,int t,int limit)
    {
        if(s == t || !limit) return limit;
        int flow = 0;
        for(int i = cur[s];i != -1;i = e[i].next)
        {
            cur[s] = i;
            if(deep[e[i].to] != deep[s] + 1) continue;
            int f = dfs(e[i].to,t,min(e[i].v,limit));
            if(f)
            {
                e[i].v -= f,e[i^1].v += f;
                flow += f,limit -= f;
                if(!limit) break;
            }
        }
        if(!flow) deep[s] = -2333333;
        return flow;
    }
    
    void dinic(int s,int t)
    {
        while(bfs(s,t)) maxflow += dfs(s,t,INF);
    }
    
    int main()
    {
        t = read();
        while(t--)
        {
            clear();
            n = read();
            rep(i,1,n) add(source,i,1),add(i,source,0),add(i+n,sink,1),add(sink,i+n,0);
            rep(i,1,n)
            rep(j,1,n) 
            {
                a = read();
                if(a) add(i,j+n,1),add(j+n,i,0);
            }
            dinic(source,sink);
            if(maxflow == n) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
  • 相关阅读:
    安卓热修复
    Activity四种启动模式
    11、网页制作Dreamweaver(补充:JS零碎知识点&&正则表达式)
    6、C#基础整理(for 语句经典习题--for循环嵌套、穷举)
    5、C#基础整理(for 语句经典习题--与 if 的嵌套)
    4、C#基础整理(if语句经典习题)
    3、C#基础整理(语句概述)
    2、C#基础整理(运算符、数据类型与转换、var关键字)
    1、C#基础整理(进制转换的方法)
    10、网页制作Dreamweaver(扩展:各浏览器对 onunload 事件的支持与触发条件实现有差异)
  • 原文地址:https://www.cnblogs.com/captain1/p/9572083.html
Copyright © 2011-2022 走看看