1.柯南开锁
-
柯南决定深入OIBH组织内部, 一探虚实.他经过深思熟虑, 决定从OIBH组织大门进入...........
OIBH组织的大门有一个很神奇的锁.锁是由M*N个格子组成, 其中某些格子凸起(灰色的格子). 每一次操作可以把某一行或某一列的格子给按下去.
如果柯南能在组织限定的次数内将所有格子都按下去, 那么他就能够进入总部. 但是OIBH组织不是吃素的, 他们的限定次数恰是最少次数
请您帮助柯南计算出开给定的锁所需的最少次数. -
这种矩阵图题目的套路就是,分为行、列两种的点集的二分图。
对于每个需要翻转的点,我们把他的行、列连一条边,表示这条边必须被覆盖。因此我们求最小点覆盖集。
代码:
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+5;
int n,m;
int nxt[N],link[N],to[N],head[N],num;
char s[105][105];
bool road[N];
void add_edge(int u,int v) {
num++; nxt[num]=head[u]; to[num]=v; head[u]=num;
}
bool Find(int u) {
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
if(!road[v]) {
road[v]=true;
if(!link[v]||Find(link[v])) {
link[v]=u;
return true;
}
}
}
return false;
}
int hungarian() {
int tot=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) road[j]=false;
if(Find(i)) tot++;
}
return tot;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) {
scanf("%s",s[i]);
for(int j=0;j<m;j++) {
if(s[i][j]=='1') {
add_edge(i+1,j+1);
}
}
}
int ans=hungarian();
printf("%d",ans);
return 0;
}
2.骑士共存问题
- 题意
- 思路:将棋盘黑白染色(呈国际象棋效果),白点与能到的黑点连边。为了保证不冲突,一条边上只能有最多一个点存在,跑最大点独立集
- 代码
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
const int N=205;
const int M=1e6+5;
int dx[9]={-2,-1,-2,-1,1,2,1,2};
int dy[9]={-1,-2,1,2,-2,-1,2,1};
bool mp[N][N];
int n,m,p[N][N],Time,road[M],tot[2];
int nxt[M],link[M],to[M],head[M],num,size[M];
void add_edge(int u,int v) {
num++; nxt[num]=head[u]; to[num]=v; head[u]=num;
}
bool Find(int u) {
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
if(road[v]!=Time) {
road[v]=Time;
if(!link[v]||Find(link[v])) {
link[v]=u;
return true;
}
}
}
return false;
}
int hungarian() {
int sum=0;
for(int i=1;i<=tot[1];i++) {
Time++;
if(Find(i)) sum++;
}
return sum;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int u,v;
scanf("%d%d",&u,&v);
mp[u][v]=true;
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(!mp[i][j]) p[i][j]=++tot[(i+j)&1];
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(!mp[i][j]&&((i+j)&1)) {
for(int d=0;d<8;d++) {
int x=i+dx[d],y=j+dy[d];
if(mp[x][y]||x<1||y<1||x>n||y>n) continue;
add_edge(p[i][j],p[x][y]);
size[p[i][j]]++;
}
}
}
}
int cnt=hungarian();
printf("%d\n",tot[1]+tot[0]-cnt);
return 0;
}
未完待续......