题目
思路:
- 当输入a—>b时,很明显如果b重复,也就是说,到b的路不止一条,就可判断不是树。(或者有人提出a和b都重复,那就更不可能是一棵树了,因为彼此联通了)
- 而我们也能发现规律,结点个数=边的个数加一
#include <iostream>
#include <cstring>
using namespace std;
int z[100005];
int main()
{
int a,b;
int num=1;
while(1)
{
int sign=0;
int jiedian=0,bian=0;
memset(z,0,sizeof(z));
while(~scanf("%d %d",&a,&b)&&a&&b){
if(a<0||b<0){
return 0;
}
if(z[b]==2){
sign=1;
}
if(z[a]==0){
jiedian++;
}
if(z[b]==0){
jiedian++;
}
z[a]=1;
z[b]=2;
bian++;
}
if(sign==0&&jiedian==bian+1)
{
printf("Case %d is a tree.\n",num++);
}
else
{
printf("Case %d is not a tree.\n",num++);
}
}
return 0;
}
题目
思路:
上联通:ABEGHJK
下联通:CDEHIJK
左联通:ACFGHIK
右联通:BDFGIJK
很明显,第一行如果是下联通,第二行对应的位置只有是上联通才能实现合并。左右联通判断的原理与之相同。
而最后统计出最高级的父节点个数,即可知道井的最小数量。
#include <iostream>
using namespace std;
char c[1000][1000];
int vis[1000000];
int find(int x){//前面的文章一直说是基本的find,vis就相当于是父节点,x也就是节点
if(x!=vis[x]){//父节点和节点的数不一样,那么就以现在的结点接着找父结点
vis[x]=find(vis[x]);
}
return vis[x];
}
void unionn(int x,int y){//合并
x=find(x);
y=find(y);
if(x!=y){
vis[y]=x;
}
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m)){
if(n<0||m<0)
break;
for(int i=0;i<n;i++)
cin>>c[i];
for(int i=0;i<n*m;i++)
vis[i]=i;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(i>=1&&(c[i][j]=='A'||c[i][j]=='B'||c[i][j]=='E'||c[i][j]=='G'||c[i][j]=='H'||c[i][j]=='J'||c[i][j]=='K'))
{
if(c[i-1][j]=='C'||c[i-1][j]=='D'||c[i-1][j]=='E'||c[i-1][j]=='H'||c[i-1][j]=='I'||c[i-1][j]=='J'||c[i-1][j]=='K'){
unionn((i-1)*m+j,i*m+j);//一列上的两个图
}
}
if(j>=1&&(c[i][j]=='A'||c[i][j]=='C'||c[i][j]=='F'||c[i][j]=='G'||c[i][j]=='H'||c[i][j]=='I'||c[i][j]=='K'))
{
if(c[i][j-1]=='B'||c[i][j-1]=='D'||c[i][j-1]=='F'||c[i][j-1]=='G'||c[i][j-1]=='I'||c[i][j-1]=='J'||c[i][j-1]=='K')
unionn(i*m+j-1, i*m+j);//一行上的两个图
}
}
}
int ans=0;
for(int i=0;i<n*m;i++){
if(vis[i]==i)//找到最高级父节点
ans++;
}
cout<<ans<<endl;
}
return 0;
}