题目:询问在给定的棋盘中能否用1×2的矩形块填满。
吐槽:由于是二分图专题中,所以毫无悬念地往二分图那边想,而且之前做多校遇到过一个类似的棋盘的题,不过那题目挺难的,是统计连通二分图的个数。
由于刚开始写二分图,所一用了比较蠢的建图方法。网上说用奇偶建图,而我用正负交替建的。
/************************************************ Author :DarkTong Created Time :2016/7/31 8:27:49 File Name :Poj_2446.cpp *************************************************/ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> #define INF 0x3f3f3f3f #define esp 1e-9 typedef long long LL; using namespace std; const int maxn = 1000; int Left[maxn], w[maxn][maxn], n, m; bool used[maxn]; bool match(int i) { for(int j=1;j<=n;++j)if(w[j][i]&&!used[j]) { used[j]=true; if(!Left[j]||match(Left[j])) { Left[j]=i; return true; } } return false; } int hungary() { int res=0; memset(Left, 0, sizeof(Left)); for(int i=1;i<=m;++i) { memset(used, 0, sizeof(used)); if(match(i)) res++; } return res; } int vis[maxn][maxn]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int r, c, p; while(scanf("%d%d%d", &r, &c, &p)==3) { memset(vis, 0, sizeof(vis)); memset(w, 0, sizeof(w)); int f, u, v, re, lre; f=re=1; lre=-1; for(int i=0;i<p;++i) { scanf("%d%d", &u, &v); vis[v][u]=INF; } if((r*c-p)&1) { puts("NO"); continue; } //建图 for(int i=1;i<=r;++i) { int f = i&1; for(int j=(f==1?1:2);j<=c;j+=2) { if(vis[i][j]==INF) continue; vis[i][j]=re++; } for(int j=(f==1?2:1);j<=c;j+=2) { if(vis[i][j]==INF) continue; vis[i][j]=lre--; } } /* for(int i=1;i<=r;++i) { for(int j=1;j<=c;++j) printf("%d ", vis[i][j]); puts(""); } */ for(int i=1;i<=r;++i) for(int j=1;j<=c;++j) { if(vis[i][j]==INF) continue; if(i>1) { u = vis[i-1][j], v=vis[i][j]; if(u!=INF) { if(u>v) swap(u, v); w[-u][v]=1; } } if(j>1) { u = vis[i][j-1], v=vis[i][j]; if(u!=INF) { if(u>v) swap(u, v); w[-u][v]=1; } } } n = -lre; m = re; n--, m--; int ans=hungary(); if(ans==n&&ans==m) puts("YES"); else puts("NO"); } return 0; }
时间: 2024-10-06 21:25:05