时间限制: 1 Sec 内存限制: 64 MB
题目描述
树是一种重要的数据结构。它要么为空,要么是一个或多个顶点的集合,这些顶点由有向边连结,并且具有如下性质: (1) 有且仅有1个结点,称为“根”。根结点没有边指向它; (2) 除根结点,每个结点仅有一条边指向它; (3) 从根到每个结点仅有一条唯一的路径。 例如,下面三个图中,第一、二个表示的是树,第三个不是。
给出顶点和有向边的信息,编一个程序判断这是一棵树吗?
输入
输入包含多组数据,每组数据格式为: 多组空格分开的整数对,每个整数对j, k(1≤j, k≤10000) 表示一条有向边从结点j指向结点k。两个空格分开的0,表示一组数据的结束。 最后一组数据后的两个空格分开的-1,表示所有输入数据的结束
输出
每组测试数据单独输出一行,输出"Case k is a tree." 或者 "Case k is not a tree." ,这里的k表示测试数据的组号,从1开始计数。
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
6 8 5 3 5 2 6 4
5 6 0 0
8 1 7 3 6 2 8 9 7 5
7 4 7 8 7 6 0 0
3 8 6 8 6 4
5 3 5 6 5 2 0 0
-1 -1
样例输出
<span id="sample_output" style="color:#333333">Case 1 is a tree.
Case 2 is a tree.
Case 3 is not a tree.</span>
反正我就在想,不是一棵树的,要么有N多个根,要么没根,要么一个节点有N多个爸爸~
于是乎,第一份代码就出炉了...
#include<cstdio>
#include<cstring>
int apprd[10005],soned[10005],a,minx,maxx,roots,failed;
int main()
{
int i,j;
while(1)
{
failed=0;
minx=10005;maxx=0;
memset(apprd,0,sizeof(apprd));
memset(soned,0,sizeof(soned));
while(1)
{
scanf("%d%d",&i,&j);
if(i==-1) return 0;
if(!i) break;
if(minx>i) minx=i;
if(minx>j) minx=j;
if(maxx<i) maxx=i;
if(maxx<j) maxx=j;
apprd[i]=apprd[j]=1;
soned[j]++;
}
roots=0;
for(i=minx;i<=maxx;i++)
{
if(apprd[i]&&soned[i]==0)
{
roots++;
if(roots>1)
{
failed=1;
break;
}
}
if(apprd[i]&&soned[i]>1)
{
failed=1;
break;
}
}
if(!roots) failed=1;
if(failed) printf("Case %d is not a tree.\n",++a);
else printf("Case %d is a tree.\n",++a);
}
}
可是......
WA的红色无情地刺痛了我的眼........
怎么会这样....
后来,发现,其实一组数据直接输入0 0的时候..它其实应该是一棵树....
没审题成千古恨啊!!!!!!!!!!!!!!
然后........再稍微处理了一下,成了:
#include<cstdio>
#include<cstring>
int apprd[10005],soned[10005],a,minx,maxx,roots,failed;
int main()
{
int i,j;
while(1)
{
failed=0;
minx=10005;maxx=-1;
memset(apprd,0,sizeof(apprd));
memset(soned,0,sizeof(soned));
while(1)
{
scanf("%d%d",&i,&j);
if(i==-1) return 0;
if(!i) break;
if(minx>i) minx=i;
if(minx>j) minx=j;
if(maxx<i) maxx=i;
if(maxx<j) maxx=j;
apprd[i]=apprd[j]=1;
soned[j]++;
}
if(minx>maxx)
{
printf("Case %d is a tree.\n",++a);
continue;
}
roots=0;
for(i=minx;i<=maxx;i++)
{
if(apprd[i]&&soned[i]==0)
{
roots++;
if(roots>1)
{
failed=1;
break;
}
}
if(apprd[i]&&soned[i]>1)
{
failed=1;
break;
}
}
if(!roots) failed=1;
if(failed) printf("Case %d is not a tree.\n",++a);
else printf("Case %d is a tree.\n",++a);
}
}
不仔细看你们可能看不出来吧.......
就是对一棵空树的特殊处理....
然后多组数据要把数组什么的该清零清零的就不说了吧
Upd:发现过不了一组数据...
1 2 2 3 3 1 4 5 0 0
不信试试?
于是:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 10005
using namespace std;
int cas,minx,maxx,fa[maxn];
bool vis[maxn];
struct node
{
int v;
node* nxt;
}*adj[maxn];
int dfs(int x)
{
int ans=1;
if(!vis[x]) return -maxn;
vis[x]=false;
for(node* p=adj[x];p!=NULL;p=p->nxt)
ans+=dfs(p->v);
return ans;
}
void addedge(int u,int v)
{
node* p=new node;
p->v=v;p->nxt=adj[u];
adj[u]=p;
}
int main()
{
int x,y;
while(1)
{
scanf("%d%d",&x,&y);
if(x<0) break;
bool f=false;
int n=0;
memset(fa,0,sizeof(fa));
memset(vis,0,sizeof(vis));
memset(adj,0,sizeof(adj));
maxx=max(x,y);minx=min(x,y);
addedge(x,y);
fa[y]=x;
if(!vis[x]) n++;
vis[x]=true;
if(!vis[y]) n++;
vis[y]=true;
while(1)
{
if(!x) break;
scanf("%d%d",&x,&y);
if(!x) break;
if(f) continue;
if(fa[y]) {f=true;continue;}
maxx=max(maxx,max(x,y));minx=min(minx,min(x,y));
addedge(x,y);
fa[y]=x;
if(!vis[x]) n++;
vis[x]=true;
if(!vis[y]) n++;
vis[y]=true;
}
int cnt=0;
for(int i=minx;i<=maxx&&!f;i++)
if(vis[i]&&!fa[i])
{
cnt++;
if(cnt>1||dfs(i)<n) f=true;
}
if(!minx&&!maxx) f=false;
if(f||cnt!=1) printf("Case %d is not a tree.\n",++cas);
else printf("Case %d is a tree.\n",++cas);
}
}

本文介绍了一个用于判断给定数据是否构成树形结构的算法。通过分析顶点与有向边的关系,确保数据满足树的定义:单一根节点、每个节点只有一个父节点及从根到每个节点的唯一路径。
482

被折叠的 条评论
为什么被折叠?



