题目描述
如题
算法
基本算法:floodfill连通块
具体实现:
看数据范围,发现不同的点之间如果要一个个判断肯定是超时的,所以要统计各个连通块的规模,不同连通块的点不可到达,乘法计算就行。统计连通块规模用floodfill,乘法计算可以用一个前缀和来优化一下。记录本题中路径的方式这里用了一个set数组。
C++ 代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<set>
#include<queue>
#define r first
#define c second
using namespace std;
typedef pair<int,int> PII;
const int N=105;
int g[N][N]; //某个点的一维坐标
int n,k,r;
set<int> S[N*N];
int cnt;
int st[N][N];
int siz[N*N]; //每种颜色的有多少个点
queue<PII> q;
const int dr[]={-1,1,0,0};
const int dc[]={0,0,-1,1};
void bfs(int r,int c){
while(!q.empty()) q.pop();
st[r][c]=cnt;
q.push({r,c});
while(q.size()){
PII t=q.front();
q.pop();
for(int i=0;i<4;i++){
int rp=t.r+dr[i];
int cp=t.c+dc[i];
if(rp<=0 || cp<=0 || rp>n || cp>n) continue;
if(st[rp][cp]) continue;
int a=g[t.r][t.c];
int b=g[rp][cp]; //存下来,然后判断是否是路径边
if(S[a].count(b) || S[b].count(a)) continue;
st[rp][cp]=cnt;
q.push({rp,cp});
}
}
}
int main(){
cin>>n>>k>>r;
int t=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=t++;
while(r--){ //把不可达的情况存到set里面
int a,b,c,d;
cin>>a>>b>>c>>d;
S[g[a][b]].insert(g[c][d]);
S[g[c][d]].insert(g[a][b]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(!st[i][j]){
cnt++;
bfs(i,j);
}
}
while(k--){
int a,b;
cin>>a>>b;
siz[st[a][b]]++;
}
for(int i=1;i<=cnt;i++){
siz[i]+=siz[i-1];
}
int res=0;
for(int i=cnt;i>=1;i--){
res+=(siz[i]-siz[i-1])*siz[i-1];
}
cout<<res;
return 0;
}