列表

详情


NC16127. 点阵

描述

源源同学酷爱玩点阵游戏。点阵游戏规则是这样的,游戏是在一个n×n的点阵上,我们每一次选择两个相邻(只包括上下左右,斜边不算)未连边的点连上一条边,如果某个时刻点阵中存在四个点,(x,y),(x+1,y),(x+1,y+1),(x,y+1),如果这四个点之间连成的边形成了一个小正方形,那么游戏此时结束。源源想要知道,对于当前一个n×n的点阵,给定一个局势(保证游戏此时没有结束),请问最多能添加多少条边,使得游戏恰好结束。


输入描述

对于每一个案例,我们第一行包括两个整数n,表示点阵的大小(2<=n<=80)。然后接下来是一个(2×n-1)×(2×n-1)的矩阵,表示当前局势

cell(2i-1,2j-1) 是一个'*'表示点阵上的点(i,j)

cell(2i,2*j) 是一个'.'表示空的空间(没有实际意义)

cell(2i,2j-1) 如果是'|'表示点(i,j)与点(i+1,j)相连,否则为'.'表示不相连

cell(2i-1,2j) 如果是'-'表示点(i,j)与点(i,j+1)相连,否则为'.'表示不相连

(1<=i,j<=n)

输出描述

输出一个数,表示源源还能最多添加多少条边,使得游戏恰好结束。

示例1

输入:

3
*-*.*
|.|.|
*.*-*
|...|
*.*.*

输出:

3

说明:

示例2

输入:

2
*.*
...
*.*

输出:

4

说明:

示例3

输入:

4
*-*-*.*
|...|..
*-*-*-*
|.....|
*.*.*-*
|.....|
*-*-*-*

输出:

5

说明:

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 18ms, 内存消耗: 1176K, 提交时间: 2023-04-21 15:20:59

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int max_n = 20000;
const int max_m = 500000;
const int inf = 2e9;
int n, m;
struct edge{
    int to, cap, rev, next;
}E[max_m];
int head[max_n];
int cnt = 1;
void add(int from, int to, int cap) {
    E[cnt].to = to;
    E[cnt].cap = cap;
    E[cnt].rev = cnt + 1;
    E[cnt].next = head[from];
    head[from] = cnt++;
    E[cnt].to = from;
    E[cnt].cap = 0;
    E[cnt].rev = cnt - 1;
    E[cnt].next = head[to];
    head[to] = cnt++;
}

int iter[max_n];
int dist[max_n];
bool searchpath(int s,int t) {
    fill(dist, dist + t + 10, -1);
    queue<int> que;que.push(s);
    dist[s] = 0;
    while (!que.empty()) {
        int u = que.front();que.pop();
        for (int i = head[u];i;i = E[i].next) {
            edge& e = E[i];
            if (dist[e.to] != -1 || e.cap == 0)continue;
            dist[e.to] = dist[u] + 1;
            que.push(e.to);
        }
    }return dist[t] != -1;
}
int matchpath(int u, int t, int f) {
    if (u == t)return f;
    for (int& i = iter[u];i;i = E[i].next) {
        edge& e = E[i];
        if (dist[e.to] <= dist[u] || e.cap == 0)continue;
        int d = matchpath(e.to, t, min(e.cap, f));
        if (d > 0) {
            e.cap -= d;
            E[e.rev].cap += d;
            return d;
        }
    }return false;
}
int dinic(int start,int ed) {
    int flow = 0;int f;
    while (searchpath(start, ed)) {
        for (int i = 1;i <= ed;++i)iter[i] = head[i];
        while (f = matchpath(start, ed, inf))
            flow += f;
    }return flow;
}

int getpoint(int x,int y) {
    return (x - 1) * (n - 1) + y;
}
bool check(int x,int y) {
    return x > 0 && x <= n - 1 && y > 0 && y <= n - 1;
}
int dirx[4] = { 1,-1,0,0 };
int diry[4] = { 0,0,1,-1 };
char mp[200][200];
int main() {
    ios::sync_with_stdio(0);
    cin >> n;
    for (int i = 1;i <= 2 * n - 1;++i)
        for (int j = 1;j <= 2 * n - 1;++j)
            cin >> mp[i][j];
    int start = (n - 1) * (n - 1) + 1;
    int ed = start + 1;
    for (int i = 1;i <= (n - 1);++i) {
        for (int j = 1;j <= (n - 1);++j) {
            int colour = ((i + j) & 1);
            int cuut = 0;
            int x = i * 2;int y = j * 2;
            for (int k = 0;k < 4;k++) {
                int xk = x + dirx[k];
                int yk = y + diry[k];
                if (mp[xk][yk] != '.')continue;
                ++cuut;
                if (colour == 0) {
                    if (check(i + dirx[k], j + diry[k]))
                        add(getpoint(i, j), getpoint(i + dirx[k], j + diry[k]), 1);
                    else add(getpoint(i, j), ed, 1);
                }
                else if (!check(i + dirx[k], j + diry[k]))
                    add(start, getpoint(i, j), 1);
            }if (colour == 0)
                add(start, getpoint(i, j), cuut - 1);
            else add(getpoint(i, j), ed, cuut - 1);
        }
    }cout << dinic(start, ed) + 1 << endl;
}

C++14(g++5.4) 解法, 执行用时: 16ms, 内存消耗: 1244K, 提交时间: 2020-08-30 10:29:58

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int max_n = 20000;
const int max_m = 500000;
const int inf = 2e9;
int n, m;
struct edge{
	int to, cap, rev, next;
}E[max_m];
int head[max_n];
int cnt = 1;
void add(int from, int to, int cap) {
	E[cnt].to = to;
	E[cnt].cap = cap;
	E[cnt].rev = cnt + 1;
	E[cnt].next = head[from];
	head[from] = cnt++;
	E[cnt].to = from;
	E[cnt].cap = 0;
	E[cnt].rev = cnt - 1;
	E[cnt].next = head[to];
	head[to] = cnt++;
}

int iter[max_n];
int dist[max_n];
bool searchpath(int s,int t) {
	fill(dist, dist + t + 10, -1);
	queue<int> que;que.push(s);
	dist[s] = 0;
	while (!que.empty()) {
		int u = que.front();que.pop();
		for (int i = head[u];i;i = E[i].next) {
			edge& e = E[i];
			if (dist[e.to] != -1 || e.cap == 0)continue;
			dist[e.to] = dist[u] + 1;
			que.push(e.to);
		}
	}return dist[t] != -1;
}
int matchpath(int u, int t, int f) {
	if (u == t)return f;
	for (int& i = iter[u];i;i = E[i].next) {
		edge& e = E[i];
		if (dist[e.to] <= dist[u] || e.cap == 0)continue;
		int d = matchpath(e.to, t, min(e.cap, f));
		if (d > 0) {
			e.cap -= d;
			E[e.rev].cap += d;
			return d;
		}
	}return false;
}
int dinic(int start,int ed) {
	int flow = 0;int f;
	while (searchpath(start, ed)) {
		for (int i = 1;i <= ed;++i)iter[i] = head[i];
		while (f = matchpath(start, ed, inf))
			flow += f;
	}return flow;
}

int getpoint(int x,int y) {
	return (x - 1) * (n - 1) + y;
}
bool check(int x,int y) {
	return x > 0 && x <= n - 1 && y > 0 && y <= n - 1;
}
int dirx[4] = { 1,-1,0,0 };
int diry[4] = { 0,0,1,-1 };
char mp[200][200];
int main() {
	ios::sync_with_stdio(0);
	cin >> n;
	for (int i = 1;i <= 2 * n - 1;++i)
		for (int j = 1;j <= 2 * n - 1;++j)
			cin >> mp[i][j];
	int start = (n - 1) * (n - 1) + 1;
	int ed = start + 1;
	for (int i = 1;i <= (n - 1);++i) {
		for (int j = 1;j <= (n - 1);++j) {
			int colour = ((i + j) & 1);
			int cuut = 0;
			int x = i * 2;int y = j * 2;
			for (int k = 0;k < 4;k++) {
				int xk = x + dirx[k];
				int yk = y + diry[k];
				if (mp[xk][yk] != '.')continue;
				++cuut;
				if (colour == 0) {
					if (check(i + dirx[k], j + diry[k]))
						add(getpoint(i, j), getpoint(i + dirx[k], j + diry[k]), 1);
					else add(getpoint(i, j), ed, 1);
				}
				else if (!check(i + dirx[k], j + diry[k]))
					add(start, getpoint(i, j), 1);
			}if (colour == 0)
				add(start, getpoint(i, j), cuut - 1);
			else add(getpoint(i, j), ed, cuut - 1);
		}
	}cout << dinic(start, ed) + 1 << endl;
}

C++ 解法, 执行用时: 14ms, 内存消耗: 1036K, 提交时间: 2022-05-06 21:42:56

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=1e5+10,INF=1e8;
int ne[M],e[M],h[N],idx;
char mp[210][210];
int f[M];
int dx[4]={0,-1,0,1},dy[4]={1,0,-1,0};
int d[N],cur[N],q[N];
int S,T;
int n;
void add(int a,int b,int c)
{
	ne[idx]=h[a],e[idx]=b,f[idx]=c,h[a]=idx++;
	ne[idx]=h[b],e[idx]=a,f[idx]=0,h[b]=idx++;
}
bool check(int x,int y)
{
	return x>0&&x<=n-1&&y>0&&y<=n-1;
}
int get(int x,int y)
{
	return (x-1)*(n-1)+y;
}
bool bfs()
{
	memset(d,-1,sizeof d);
	int hh=0,tt=0;
    d[S]=0,q[0]=S;
    cur[S] = h[S];
    while(hh<=tt)
    {
    	int t=q[hh++];
    	for(int i=h[t];~i;i=ne[i])
    	{
    		int j=e[i];
    		if(f[i]&&d[j]==-1)
    		{    
    		    d[j]=d[t]+1;
    			 cur[j]=h[j];
    			if(j==T)return true;
                 q[++tt]=j;
    		}
    	}
    }
    return false;
}
int find(int u,int limit)
{
	if(T==u)return limit;
	int flow=0;
	for(int i=cur[u];~i&&flow<limit;i=ne[i])
       {
       		int j=e[i];
       		 cur[u]=i;
       		if(d[j]==d[u]+1&&f[i])
       		{
       			int t=find(j,min(f[i],limit-flow));
       			if(!t)d[j]=-1;
       			f[i]-=t,f[i^1]+=t;
       			flow+=t;
       		}
       }
       return flow;
}
int dinic()
{
	int r=0;
	int flow;
	while(bfs())while(flow=find(S,INF))r+=flow;
	return r;
}
int main()
{	
   memset(h,-1,sizeof h);
   cin>>n;
   for(int i=1;i<=2*n-1;i++)
   	for(int j=1;j<=2*n-1;j++)
   	    cin>>mp[i][j];
   	 S=(n-1)*(n-1)+1;
   	 T=S+1;
   	for(int i=1;i<=n-1;i++)
   	 for(int j=1;j<=n-1;j++)
   	 {
   	 	int color=((i+j)&1);
   	 	int cnt=0;
   	 	int x=i*2,y=j*2;
   	 	for(int k=0;k<4;k++)
   	 	{
   	 		int nx=dx[k]+x,ny=dy[k]+y;
   	 		if(mp[nx][ny]!='.')continue;
   	 		cnt++;
   	 		if(color==0)
   	 		{
   	 			if(check(i+dx[k],j+dy[k]))
   	 				add(get(i,j),get(i+dx[k],j+dy[k]),1);
   	 			else add(get(i,j),T,1);
   	 		}
   	   	else if(!check(i+dx[k],j+dy[k]))add(S,get(i,j),1);
   	 	}
   	 	 if(color==0)add(S,get(i,j),cnt-1);
   	 	 else add(get(i,j),T,cnt-1);
   	 }
   	 cout<<dinic()+1<<endl;
   	 return 0;
}	

上一题