[LibreOJ Round #11]Misaka Network 与测试
壹、题目
贰、思考
要求有几个:
- 矩阵不交;
- 平均值为 \(2\);
- 不能有
*
;
如果没有要求 \(2\),要求最多的矩阵,不就输出......
有要求 \(2\),首先较为贪心地考虑,有 \(2\) 就自成一个矩阵?这样会出问题吗?比如为了让 \(2\) 自成一个矩阵,破坏了更多矩阵?但是我们破坏了一个矩阵,也让一个 \(2\) 自成了矩阵,就这样考虑似乎是不会出问题的。
然后,对于一个 \(3\),它必定会和一个 \(1\) 配对,对于 \(1\) 也是如此,贪心地,一个 \(1\) 和一个 \(3\) 配对是最优的,并且为了使测试尽可能多,矩阵尽量小,所以 "相邻" 的 \(1,3\) 配一起?所以这只是一个简简单单的二分图匹配?\(\text{have a try}\)......然后......就过了......
细细想一下,好像确实是这个样子的,因为无论什么情况,只要一个矩阵中划分出多于一组的 \(\lang 1,3\rang\),就可以拆成至少也是等价个数,甚至有可能会更多的矩阵数量。
所以这个贪心应该是对的 因为我想不出反例 。
叁、代码
using namespace Elaina;
const int maxn=1e5;
int n,m,ans;
int** a;
char c[maxn+5];
inline void input(){
n=readin(1),m=readin(1);
a=new int*[n+5];
rep(i,1,n)a[i]=new int[m+5];
rep(i,1,n){
scanf("%s",c+1);
rep(j,1,m){
if(c[j]=='*')a[i][j]=-1;
else a[i][j]=c[j]-'0';
ans+=(a[i][j]==2);
}
}
}
int dir[][2]={{0,1},{0,-1},{-1,0},{1,0}};
inline int getid(const int i,const int j){
return (i-1)*m+j;
}
struct edge{int to,nxt;
edge(const int T=0,const int N=0):to(T),nxt(N){}
}e[maxn+5];
int tail[maxn+5],ecnt;
inline void add_edge(const int u,const int v){
e[++ecnt]=edge(v,tail[u]);tail[u]=ecnt;
}
inline int inside(const int x,const int y){
return 0<x && x<=n && 0<y && y<=m;
}
inline void build(){
rep(i,1,n)rep(j,1,m)if(a[i][j]==1){
for(int k=0;k<4;++k){
int tx=i+dir[k][0];
int ty=j+dir[k][1];
if(!inside(tx,ty))continue;
if(a[tx][ty]==3)add_edge(getid(i,j),getid(tx,ty));
}
}
}
int vis[maxn+5],match[maxn+5];
int dfs(const int u){
for(int i=tail[u],v;i;i=e[i].nxt)if(!vis[v=e[i].to]){
vis[v]=1;
if(!match[v] || dfs(match[v])){
match[v]=u;
return 1;
}
}
return 0;
}
inline void hungary(){
for(int i=1;i<=n*m;++i){
memset(vis+1,0,(n*m)<<2);
if(dfs(i))++ans;
}
writc(ans,'\n');
}
signed main(){
input();
build();
hungary();
return 0;
}
肆、用到の小 \(\tt trick\)
可以先从题目的一些性质、特征贪心地入手,这样可能对思路有所启发.