您的位置:首页 > 其它

bzoj 4651 网格

2017-07-05 10:05 232 查看

4651: [Noi2016]网格

Time Limit: 50 Sec  Memory Limit: 1024 MB
Submit: 147  Solved: 107

[Submit][Status][Discuss]

Description

跳蚤国王和蛐蛐国王在玩一个游戏。
他们在一个 n 行 m 列的网格上排兵布阵。其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐,其余的格子中,每个格子有一只跳蚤。
我们称占据的格子有公共边的两只跳蚤是相邻的。
我们称两只跳蚤是连通的,当且仅当这两只跳蚤相邻,或存在另一只跳蚤与这两只跳蚤都连通。
现在,蛐蛐国王希望,将某些(0 个,1 个或多个)跳蚤替换成蛐蛐,使得在此之后存在至少两只跳蚤不连通。
例如:我们用图

表示一只跳蚤,用图

表示一只蛐蛐,那么图
1 描述了一个 n=4,m=4,c=2的情况。
这种情况下蛐蛐国王可以通过将第 2 行第 2 列,和第 3 行第 3 列的两只跳蚤替换为蛐蛐,从而达成他的希望,如图 2 所示。并且,不存在更优的方案,但是可能存在其他替换 2 只跳蚤的方案。
你需要首先判断蛐蛐国王的希望能否被达成。如果能够达成,你还需要最小化被替换的跳蚤的个数。


 


Input

每个输入文件包含多组数据。
输入文件的第一行只有一个整数 TT,表示数据的组数。保证 1≤T≤20。
接下来依次输入 TT 组数据,每组数据的第一行包含三个整数 n, m, c。
保证1≤n,m≤10^9,0≤c≤min(nm,105)
接下来 c行,每行包含两个整数 x, y表示第 x 行,第 y 列的格子被一个蛐蛐占据(1≤x≤n,1≤y≤m)每一组数据当中,同一个蛐蛐不会被多次描述。
同一行相邻的整数之间由一个空格隔开。
1≤n,m≤10^9, 0≤c≤nm, 1≤x≤n, 1≤y≤m
1≤T≤20。我们记 ∑c为某个测试点中,其 T 组输入数据的所有 c 的总和,∑c≤10^5

Output

对于每一组数据依次输出一行答案。
如果这组数据中,蛐蛐国王的希望不能被达成,输出-1。否则,输出被替换的跳蚤的个数的最小值

Sample Input

4

4 4 2

1 1

4 4

2 3 1

1 2

2 2 2

1 1

2 2

1 1 0

Sample Output

2

1

0

-1

explanation

第一组数据就是问题描述中的例子。

对于第二组数据,可以将第 2 行第 2 列的一只跳蚤替换为蛐蛐,从而使得存在两只跳蚤不连通

并且不存在更优的方案。

对于第三组数据,最初已经存在两只跳蚤不连通,故不需要再进行替换。

对于第四组数据,由于最多只有一只跳蚤,所以无论如何替换都不能存在两只跳蚤不连通

HINT

Source

【分析】

摔。破题抄一年。

http://blog.csdn.net/crzbulabula/article/details/54016812

自己写不对...苦恼.jpg

【代码】

//NOI 2016 网格
#include<bits/stdc++.h>
#define LL long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
const int mxn=2500005;
bool flag;
int n,m,c,T,tot,tim,num,cnt;
bool vis[mxn],bo[mxn],yes[mxn];
int dx[9]={0,-1,0,0,1,-1,-1,1,1};
int dy[9]={0,0,1,-1,0,1,-1,1,-1};
int bel[mxn],dfn[mxn],low[mxn],ccz[mxn];
struct point
{
int x,y;
bool operator < (const point &b) const
{
if(x<b.x) return 1;
if(x>b.x) return 0;
return y<b.y;
}
}p[mxn],q[mxn];
vector <LL> v0[mxn],v1[mxn],node[mxn];
inline LL P(int x,int y) {return (LL)x*m+y;}
map <point,int> m1,m2;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x;
}
inline void Dfs(int u)
{
bel[u]=num;
for(int i=0;i<v0[u].size();i++)
{
int v=v0[u][i];
if(bo[v]) continue;
bo[v]=1,Dfs(v);
}
}
inline void dfs(int u,int fa)
{
int son=0;
ccz[u]=cnt;
dfn[u]=low[u]=(++tim);
for(int i=0;i<v1[u].size();i++)
{
int v=v1[u][i];
if(v==fa) continue;
if(!dfn[v])
{
dfs(v,u),son++;
low[u]=min(low[u],low[v]);
if(dfn[u]<=low[v]) yes[u]=1;
}
else low[u]=min(low[u],dfn[v]);
}
if(fa==0 && son==1) yes[u]=0;
}
inline bool check(int u)
{
int nx=q[u].x,ny=q[u].y;
fo(j,1,8)
{
int ex=nx+dx[j],ey=ny+dy[j];
point tmp=(point){ex,ey};
// printf("(%d %d) (%d %d)\n",nx,ny,ex,ey);
if(m1.count(tmp)) return 1;
}
return 0;
}
inline bool connect()
{
fo(i,1,c)
fo(j,1,8)
{
point g=(point){p[i].x+dx[j],p[i].y+dy[j]};
if(m1.count(g)) v0[i].push_back(m1[g]);
}
fo(i,1,c) if(!bo[i]) bo[i]=1,num++,Dfs(i);
fo(i,1,c) fo(x,-2,2) fo(y,-2,2)
{
point g=(point){p[i].x+x,p[i].y+y};
if(g.x<=0 || g.x>n || g.y<=0 || g.y>m) continue;
if(!m1.count(g) && !m2.count(g))
{
q[++tot]=g,m2[g]=tot;
node[bel[i]].push_back(tot);
}
}
fo(i,1,tot) fo(j,1,4)
{
point g=(point){q[i].x+dx[j],q[i].y+dy[j]};
if(m2.count(g)) v1[i].push_back(m2[g]);
}
fo(i,1,tot) if(!dfn[i]) cnt++,dfs(i,0);
fo(i,1,tot) if(yes[i] && check(i)) flag=1;
fo(i,1,num) for(int j=1;j<node[i].size();j++)
{
int now=node[i][j],pre=node[i][j-1];
if(ccz[now]!=ccz[pre]) return 0;
}
return 1;
}
inline void clear()
{
m1.clear(),m2.clear();
fo(i,1,c) v0[i].clear(),bo[i]=bel[i]=0;
fo(i,1,c) node[i].clear();
fo(i,1,tot) dfn[i]=low[i]=yes[i]=0;
fo(i,1,tot) v1[i].clear();
tot=tim=num=cnt=flag=0;
}
int main()
{
T=read();
while(T--)
{
clear();
n=read(),m=read(),c=read();
fo(i,1,c)
{
p[i].x=read(),p[i].y=read();
m1[p[i]]=i;
}
if((LL)n*m-c<=1) {puts("-1");continue;}
if(!connect()) {puts("0");continue;}
if((LL)n*m-c==2) {puts("-1");continue;}
if(n==1 || m==1) flag=1;
if(flag) puts("1");else puts("2");
}
return 0;
}
/*
1
1000000000 1000000000 2
1 999999999
2 1000000000
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: