题目描述:
题意比较麻烦.核心是通过改变开关的横竖来使得从左上到左下可以走到,并且是走一次就能够遍历所有的点恰好一次.
http://acm.bnu.edu.cn/v3/contest_show.php?cid=6416#problem/F
题解:
首先是正解怎么做:(1)转化为联通即可. 一单联通,除了左上和左下的点,其他的点都度都是2.s和t的点是1.那么一但联通,一定满足有一条路径只经过并且都经过每个点一次.(2)怎么贪心的搞联通?这道题目数数初始状态的联通块的数目-1就是答案. 因为相邻的两个联通块随便改一个相邻的墙一定会两个快联通.可以在纸上画一下,题目的开关的性质导致.
其次,比赛时想成网络流…总结如下:
(1)k覆盖模型只能右下(单一不重复即可),不能四个方向都能走.因为像这道题目用k覆盖的模型,就会有4-5-4的环.我们是不能通过网络流来排除的.(并且费用流根本就不能描述开关的花费…哎…..)
(2)k覆盖有两种做法. 两种限制遍历过所有点的限制不同.
(3)欧拉通路. 欧拉回路. 偶然看到网络流解混合图变成欧拉通路
重点:
(1)猜想是不是搞的联通就ok了? 然后用度的性质.
(2)猜想是不是联通块-1就行了?首先是差不多,其次画图推.
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const int maxn = 1000+10;
const int MAXN = 600*601+10;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int vis[maxn][maxn];
int n, m, k;
int a[maxn][maxn];
int cnt;
struct info
{
int x, y;
info(int _x=0, int _y=0)
{
x = _x;
y = _y;
}
};
queue<info> q;
int check(int x, int y)
{
if(x>=0&&x<n&&y>=0&&y<m)
return 1;
return 0;
}
void bfs(int ux, int uy)///要用bfs.... 写的麻烦了...
{
//printf("dfsd %d %d\n", ux, uy);
vis[ux][uy] = 1;
while(!q.empty())
{
q.pop();
}
q.push(info(ux, uy));
while(!q.empty())
{
int x = q.front().x, y = q.front().y;
q.pop();
if((x+y)%2==0)
{
int pI, pJ, newI, newJ;
pI = x, pJ = y;
if(a[pI][pJ]==1||a[pI][pJ]==0)
{
newI = x, newJ = y-1;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
if(a[pI][pJ]==2||a[pI][pJ]==0)
{
newI = x-1, newJ = y;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
pI = x+1, pJ = y+1;
if(a[pI][pJ]==1||a[pI][pJ]==0)
{
newI = x, newJ = y+1;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
if(a[pI][pJ]==2||a[pI][pJ]==0)
{
newI = x+1, newJ = y;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
}
else
{
int pI, pJ, newI, newJ;
pI = x, pJ = y+1;
if(a[pI][pJ]==1||a[pI][pJ]==0)
{
newI = x, newJ = y+1;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
if(a[pI][pJ]==2||a[pI][pJ]==0)
{
newI = x-1, newJ = y;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
pI = x+1, pJ = y;
if(a[pI][pJ]==1||a[pI][pJ]==0)
{
newI = x, newJ = y-1;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
if(a[pI][pJ]==2||a[pI][pJ]==0)
{
newI = x+1, newJ = y;
if(check(newI, newJ)&&!vis[newI][newJ])
{
vis[newI][newJ] = 1;
q.push(info(newI, newJ));
}
}
}
}
}
void solve()
{
CLR(vis);
cnt = 0;
REP(i, 0, n)
{
REP(j, 0, m)
{
if(!vis[i][j])
{
cnt++;
bfs(i, j);
}
}
}
printf("%d\n", cnt-1);
}
char str[maxn];
int main()
{
// freopen("6Fin.txt", "r", stdin);
//freopen("6Fout.txt", "w", stdout);
while(scanf("%d", &k) != EOF)
{
CLR(a);
n = 2*k;
m = 2*k+1;
REP_D(i, 1, 2*k - 1)
{
int start = 2;
if(i&1)
{
start = 1;
}
scanf("%s", str);
for(int j = start, t = 0; t<k; t++,j += 2)
{
if(str[t]=='H')
{
a[i][j] = 1;
}
else
{
a[i][j] = 2;
}
}
}
solve();
}
return 0;
}