1. 程式人生 > >P2055 [ZJOI2009]假期的宿舍 - 二分圖最大匹配

P2055 [ZJOI2009]假期的宿舍 - 二分圖最大匹配

match 二分 ons dfs 的人 clu 數據 自己的 algo

把人和床分開考慮,題目說每個人只能睡和自己直接認識的人的床,就是一種邊的關系,但是並不是人與人,實際上人與人之間連邊是很難處理的,但是如果把人和床連邊,就是一張二分圖,左右兩邊分別是不同的東西,然後求一下最大匹配就好了
沒思路的時候換換角度,看能不能搞出什麽“新東西”來
註意多組數據不超時的情況下能用memset盡量用,有時候感覺某個數組可以不清空但實際上是需要清空的
還有註意連邊的時候沒那麽簡單。。。看註釋吧

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 210;

int n,m,match[MAXN],ans,edge_tot,tot,outnum,last[MAXN],vis[MAXN],gra[MAXN][MAXN],house[MAXN]; 
int sch[MAXN],t,bad[MAXN];

struct Edge{
    int u,v,to;
    Edge(){}
    Edge(int u, int v, int to) : u(u), v(v), to(to) {}
}e[10010];

inline void add(int u, int v) {
    e[++edge_tot] = Edge(u, v, last[u]);
    last[u] = edge_tot;
}

bool dfs(int x) {
    for(int i=last[x]; i; i=e[i].to) {
        int v = e[i].v;
        if(vis[v]) continue;
        vis[v] = 1;
        if(!match[v] || dfs(match[v])) {
            match[v] = x;
            return true;
        }
    }
    return false;
}

int main() {
    scanf("%d", &t);
    while(t--) {
        
        ans = 0, edge_tot = 0, outnum = 0;
        memset(match, 0, sizeof(match));
        memset(last, 0, sizeof(last));
        memset(house, 0, sizeof(house));
        memset(sch, 0, sizeof(sch));
        
        scanf("%d", &n);
        for(int i=1; i<=n; i++) {
            scanf("%d", &sch[i]);
        }
        for(int i=1; i<=n; i++) {
            int temp_sca = 0;
            if(sch[i] == 1) scanf("%d", &house[i]);
            else scanf("%d", &temp_sca), outnum++;
            if(!house[i] && sch[i]) {//和自己的床連邊,首先i得有床,其次得不回家
                outnum++;
                add(i, i+n);
                add(i+n, i);
            }
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                scanf("%d", &gra[i][j]);
                if(gra[i][j] && sch[j] && house[i] == 0) {
                    add(i, j+n);//i這個人和j的床位連邊,需要i不是回家的人並且j是有床的(j不一定必須回家)
                    add(j+n, i);
                }
            }
        }
        for(int i=1; i<=n; i++) {
            if(!house[i]) {
                memset(vis, 0, sizeof(vis));
                if(dfs(i)) ans++;
            }
        }
        if(ans == outnum) {
            printf("^_^\n");
        } else printf("T_T\n");
    }
    return 0;
} 

P2055 [ZJOI2009]假期的宿舍 - 二分圖最大匹配