[TJOI2010] 打扫房间

无序

正文

我们对此题观察,但是没什么好的方法

其实一开始会有几个想法:

  1. 搜索骗分
  2. 肯定是关于图的算法:
    • 拓扑(跟度有关?
    • 流算法
    • 结论题??
  3. 打表??

我先想的搜索,就是说,这个东西能搜成环就搜,但是,不太行,好像不好搜呀。。

然后想拓扑,因为,每个点的度都是二,然后,,没有什么想法。。我们再想想 flow ,好像 ok

怎么建图,我们通过一个题目的描述,可以知道,每条边,都有2的流量代表进出一次,然后黑白染色,就行了

/* make by ltao */
const int Maxn=33;
#define Max Maxn*Maxn
int tt,n,m,h[Max],cnt,s,t,tot,gap[Max],dep[Max],maxflow;
bool flag[Max];
char ch;
struct Edge{
    int to,lac,flow;
    void insert(int x,int y,int z){to=y;lac=h[x];h[x]=cnt++;flow=z;}
}edge[Max*5];
void add_edge(int x,int y,int z){
    edge[cnt].insert(x,y,z);
    edge[cnt].insert(y,x,0);
}
void bfs(int s,int t){
    memset(dep,-1,sizeof dep);
    gap[0]=1;dep[t]=0;
    queue<int> q;q.push(t);
    while(!q.empty()){
        int fr=q.front();q.pop();
        for(int i=h[fr];i!=-1;i=edge[i].lac){
            int to=edge[i].to;
            if(dep[to]!=-1) continue;
            dep[to]=dep[fr]+1;
            gap[dep[to]]++;
            q.push(to);
        }
    }
    return ;
}
int dfs(int u,int min1){
    if(u==t) return min1;
    int sum=min1;
    for(int i=h[u];i!=-1;i=edge[i].lac){
        int to=edge[i].to;
        if(!edge[i].flow||dep[to]+1!=dep[u]) continue;
        int ret=dfs(to,min(sum,edge[i].flow));
        sum-=ret;edge[i].flow-=ret;edge[i^1].flow+=ret;
        if(!sum) return min1;
    }
    gap[dep[u]]--;
    if(!gap[dep[u]]) dep[s]=tot;
    gap[++dep[u]]++;
    return min1-sum;
}
void ISAP(int s,int t){
    bfs(s,t);
    while(dep[s]<tot)
        maxflow+=dfs(s,0x3f3f3f3f);
}
#define id(i,j) ((i-1)*m+j)
int main(){
//  freopen("p2123.in","r",stdin);
//  freopen("p2123.out","w",stdout);
    tt=read();
    while(tt--){
        memset(flag,0,sizeof flag);
        n=read();m=read();
        s=0;t=n*m+1;
        maxflow=0;tot=n*m;
        for(int i=1;i<=n*m;++i){
            ch=Get();
            if(ch=='#') flag[i]=1,tot--;
        }
        // 定义
        // the chesses which is its (i+j)%2 are black,else are white
        // and s -> black,white->t
        memset(h,-1,sizeof h);cnt=0;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j){
                int id=(i-1)*m+j;
                if(flag[id]) continue;
                if((i+j)%2){
                    add_edge(s,id,2);
                    if(i>1&&!flag[id(i-1,j)]) add_edge(id,id(i-1,j),1);
                    if(i<n&&!flag[id(i+1,j)]) add_edge(id,id(i+1,j),1);
                    if(j>1&&!flag[id(i,j-1)]) add_edge(id,id(i,j-1),1);
                    if(j<m&&!flag[id(i,j+1)]) add_edge(id,id(i,j+1),1);
                }
                else add_edge(id,t,2);
            }
        // 终于建好图了
        ISAP(s,t); 
        if(maxflow<tot) printf("NO\n");
        else printf("YES\n");
    }
    return  0;
}

以后都不准备加头文件了,咕

其实TJOI 每年都有网络流,抓住机会。

猜你喜欢

转载自www.cnblogs.com/zhltao/p/12367301.html