PPOJ刷题-2
1118: 继续畅通工程(kruskal)
题目描述
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
输入
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
输出
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
样例输入
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
样例输出
3
1
0
#include<bits/stdc++.h>
using namespace std;
const int N=105;
struct Edge{
int s,e,len;
}edge[N*(N-1)/2];
int n,m,father[N];//分别表示点数,边数,和并查集情况
int findfd(int x)
{
if(father[x]==x)
return x;
return findfd(father[x]);
}
int cmp(Edge a,Edge b)//按照边长进行排序
{
return a.len<b.len;
}
int Kruskal(int m)
{
sort(edge+1,edge+m+1,cmp);//对边进行排序
int cost=0;
for(int i=1;i<=m;i++){//边数刚好构成最小生成树
int x=findfd(edge[i].s);
int y=findfd(edge[i].e);
if(x!=y){
father[x]=y;
cost+=edge[i].len;
}
}
return cost;
}
int main()
{
while(cin>>n&&n){
for(int i=1;i<=n;i++)
father[i]=i;
m=n*(n-1)/2;
for(int i=1;i<=m;i++){
int c,d;
cin>>edge[i].s>>edge[i].e>>c>>d;
if(!d) edge[i].len=c;
else edge[i].len=0;
}
printf("%d\n",Kruskal(m));
}
return 0;
}
1138: N皇后问题(DFS)
题目描述
在一个N*N的棋盘上,问你有多少不同的方式摆放N个皇后。
每个皇后所处的行、列、两条对角线上都不能有其他皇后。
输入
无需处理到EOF
一个整数N,3<=N<=13
输出
输出不同的方案数
样例输入
4
样例输出
2
#include<bits/stdc++.h>
using namespace std;
int col[32],r[32],l[32];//分别标记行,主对角线和副对角线
int n,ans=0;
void DFS(int row)//每行遍历
{
if(row==n+1){
ans++;
return;
}
for(int i=1;i<=n;i++){
if(!col[i]&&!r[i-row+n]&&!l[i+row])//+n是防止数组越界
{
col[i]=r[i-row+n]=l[i+row]=1;
DFS(row+1);
col[i]=r[i-row+n]=l[i+row]=0;
}
}
}
int main()
{
cin>>n;
DFS(1);
cout<<ans<<endl;
return 0;
}
1286: PIPI运货(Floyd)
题目描述
PIPI是一个商人,经常需要将货物从A地运到B地,我们可以把PIPI经常活动的区域抽象成一个n个结点的地图,用一个nxn的矩阵表示。
矩阵第i行第j列的值代表PIPI从 i 地将货物运到 j 地所需要的固定费用,若该值为-1则代表 i 和 j之间没有直接的通路,注意道路是双向的。
除了上述固定费用外,PIPI在经过每一个结点时都需要交一次过路费(起点和终点不需要交过路费)。
作为一个精打细算的商人,你能帮PIPI计算出从A地到B地的最少费用是多少吗?
输入
第一行输入结点数目n (0<n<=100)
接下来n行输入一个nxn的矩阵(矩阵的值不大于1000)。
第n+2行输入n个数,代表每个结点的过路费cost(cost<=1000)。
第n+3行输入一个数q (q<=10000),代表PIPI的询问次数。
接下来q行,每行输入两个数字,询问A到B的最少花费。
输出
输出q个数字,代表q次询问的结果。若询问的两个地点不可达,输出-1.
样例输入
5
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
3
1 3
3 5
2 4
样例输出
21
16
17
#include<bits/stdc++.h>
using namespace std;
const int INF=1e8;
int R[102][102],C[102];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int k;
cin>>k;
R[i][j]=(k==-1?INF:k);
}
}
for(int j=1;j<=n;j++)
cin>>C[j];
for(int k=1;k<=n;k++){//其中的k表示i->j中所经过的点,如果路径长度小就更新
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(R[i][k]+R[k][j]+C[k]<R[i][j])
R[i][j]=R[i][k]+R[k][j]+C[k];
}
}
}
int m;
cin>>m;
while(m--){
int x,y;
cin>>x>>y;
cout<<R[x][y]<<endl;
}
return 0;
}
1304: 盗窃团伙(Floyd)
题目描述
美丽祥和的CSU校园里有许多门面,每个门面都出租给做生意的商户,商户之间都在做着各自的生意。但是在宁静的校园里也会有邪恶势力存在。CSU存在着一个盗窃团伙麓石开,盗窃团伙为首的是鸡腿和xiefang,他们总是想着如何去盗窃所有门面商户的商品,然后疯狂的盗取别人的劳动成果。
现在给定n个门面的路线图,若门面i和门面j有一条直接通路,那么在图里面我们用一条无向边来表示i和j可达,边上的权值是门面i和门面j的道路长度。现在鸡腿和xiefang准备在n个门面中选定一个门面租赁,便于偷窃其他所有门面的商品,所以他们对租赁门面的要求是,距离他们租赁门面最远的门面到该门面的路程最短。试问他们应该租赁哪一个门面。
输入
输入第一行包括两个数字n和m , 分别代表CSU的门面数目和门面之间的路径数目( n<=500 m <=10000)。
接下来m行每行输入三个数字 u v w ,代表门面u和门面v之间的距离是w。(1<=u,v <=n , 1<=w <=1000)
输出
输出他们会租赁的门面和与该门面相距最远门面的距离,若有多个合法门面,则输出编号最小的那一个。若他们无法偷窃所有的门面,输出"What a pity!"
样例输入
3 3
1 2 3
1 3 4
2 3 1
样例输出
2 3
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int mp[505][505],fa[505],n,m;
int find_F(int x){
if(fa[x]!=x)
fa[x]=find_F(fa[x]);
return fa[x];
}
void Floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(mp[i][k]+mp[k][j]<mp[i][j])
mp[i][j]=mp[i][k]+mp[k][j];
}
}
}
}
void solve()
{
Floyd();
int center_ans=1,Ans=INF;
for(int center=1;center<=n;center++){//查找一点到某一点的最远的最小距离
int MaxDis=0;
for(int j=1;j<=n;j++){
MaxDis=max(MaxDis,mp[center][j]);
}
if(Ans>MaxDis){
Ans=min(Ans,MaxDis);
center_ans=center;
}
}
printf("%d %d\n",center_ans,Ans);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
fa[i]=i;
for(int j=1;j<=n;j++){
mp[i][j]=(i==j?0:INF);
}
}
for(int i=1;i<=m;i++){
int x,y,c;
cin>>x>>y>>c;
mp[x][y]=mp[y][x]=c;
if(find_F(x)!=find_F(y))
fa[x]=fa[y];
}
int cnt=0;
for(int i=1;i<=n;i++)
if(fa[i]==i) cnt++;
if(cnt>1)
printf("What a pity!\n");
else
solve();
return 0;
}
1306: 盗窃团伙II(Kruskal)
题目描述
听说PIPI家又有新产品了,盗窃团伙麓石开的鸡腿和xiefang开始计划着要去PIPI家偷产品了。要是偷到了,他们就可以把PIPI家的产品理不直气也壮的高价售出了!!!
CSU的地下有二战时构建的地下交通网络,交通网络中有n个枢纽,m条隧道,每个隧道都连接了两个交通枢纽。麓石开团伙在 1 号枢纽,而PIPI家的产品中心刚好位于n号枢纽,现在他们准备从地下隧道直通PIPI家的产品中心。但是这些隧道已经年久失修,需要翻新一遍才能够安全通过。现在麓石开想请若干家施工公司将其中的一些隧道翻新,使得他们能够从 1 号枢纽走到 n 号枢纽。这些施工公司能够同时开工翻新隧道,但是每一家公司都只能翻新一条隧道。 (两个枢纽之间可能有多条隧道)
麓石开只想着尽可能早一点的偷到PIPI家的新产品,请问至少需要多少天,他们才能够修通隧道,进入PIPI家的产品中心偷产品??
输入
输入的第一行包含两个整数n, m,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量 (n<=1e5 , m<=2e5)。
第2行到第m+1行,每行包含三个整数a, b, c,表示枢纽a和枢纽b之间可以修建一条隧道,需要的时间为c天 (1<=a,b<=n , 0<c<=1e5)。
输出
输出盗窃团伙至少需要多少天才能偷到PIPI家的产品?若PIPI足够幸运,让他们没有办法偷到产品,则输出"How lucky!"
样例输入
6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6
样例输出
6
提示
然鹅PIPI并没有 How lucky 的时候 ,o(╥﹏╥)o
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int fa[N],n,m;
struct edge{
int s,e,c;
}s[2*N];
int cmp(edge a,edge b)
{
return a.c<b.c;
}
int find_f(int x)//压缩版并查集
{
return fa[x]==x?x:fa[x]=find_f(fa[x]);
}
int Kruskal(){
sort(s,s+m,cmp);
for(int i=0;i<m;i++){
if(find_f(s[i].s)!=find_f(s[i].e)){
fa[find_f(s[i].s)]=find_f(s[i].e);
}
if(find_f(1)==find_f(n))//找到最少修建好1到n所需的时间
return s[i].c;
//因为是从小到大排序,如果1到n所需时间短就会马上输出
//如果所需时间长,在构建最小生成树的过程中就会输出
//不管如何所需最少时间都是此刻所连接了1到n的路径时间
}
return -1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=0;i<m;i++){
cin>>s[i].s>>s[i].e>>s[i].c;
}
int ans=Kruskal();
if(ans==-1)
printf("How lucky!\n");
else
printf("%d\n",ans);
return 0;
}
1337: 汉诺塔问题(递归)
题目描述
假设有三个分别命名为A、B和C的塔座,在塔座X上插有n个直径大小各不相同、依小到大编号为1,2,…,n的圆盘。现要求将A轴上的n个圆盘移至塔座C上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则:
1)每次只能移动一个圆盘;
2)圆盘可以插在A、B和C中的任一塔座上;
3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。
输入
输入包含多组测试用例。
每组样例输入一个正整数n (n<=15)
输出
对于每组测试样例,输出每一步如何进行移动。
样例输入
1
2
3
样例输出
Move disk 1 from A to C
Move disk 1 from A to B
Move disk 2 from A to C
Move disk 1 from B to C
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
#include<bits/stdc++.h>
using namespace std;
int n;
void Move(char x,int n,char y){
printf("Move disk %d from %c to %c\n",n,x,y);
}
void hanoi(int n,char x,char y, char z)
{
if(n==1) Move(x,1,z);
else {
hanoi(n-1,x,z,y);//先将上面n-1个小盘子从A柱经过C柱放到B柱上
Move(x,n,z);//将最底层的盘子从A柱放到C柱
hanoi(n-1,y,x,z);//将剩下的n-1个盘子从B柱经过A柱放到C柱
}
}
int main()
{
while(cin>>n){
hanoi(n,'A','B','C');
printf("\n");
}
return 0;
}
1273: 三个有序数组的交集
题目描述
现在有三个有序数组 A , B ,C ,请你求出他们的交集。
输入
第一行输入三个正整数 n , m , q 表示三个有序数组的大小 (1<=n,m,q<=1e5)。
第二行输入数组A。
第三行输入数组B。
第四行输入数组C。
输出
输出一行,表示他们的交集,元素之间以空格分割。
样例输入
5 5 5
1 2 3 4 5
1 2 5 7 9
1 3 4 5 8
样例输出
1 5
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int main()
{
//i、j、k分别为遍历三个数组的指针,x为指向元素的最小值
int i,j,k;
int x,n,m,q;
int A[N],B[N],C[N];
cin>>n>>m>>q;
for(i=0;i<n;i++)
cin>>A[i];
for(i=0;i<m;i++)
cin>>B[i];
for(i=0;i<q;i++)
cin>>C[i];
//三个指针分别从起点开始遍历,f初始化为0,当其中一个指针到达终点时就停止遍历
for(int f=i=j=k=0;i<n&&j<m&&k<q;){
//若三个指针指向元素相等,则该元素在交集中,输出即可
if(A[i]==B[j]&&B[j]==C[k]){
if(f) printf(" ");
f=1,printf("%d",A[i]);
i++,j++,k++;
}//若有不相等
else{
// x为三指针指向元素最小的那个
x=min(A[i],min(B[j],C[k]));
if(x==A[i]) i++;
if(x==B[j]) j++;
if(x==C[k]) k++;
}
}
printf("\n");
return 0;
}
1295: 一元多项式乘法
题目描述
使用链表实现两个一元多项式A和B的乘法。
输入
第一行输入一个正整数N(0<N<=500),代表链表A中结点的个数。
第二行输入2N个整数,输入的形式为 coffi expi, 代表每一项的系数和指数,输入保证对于任意 i≠j, coffi≠coffj ( 0<|coffi|<1000 , 0<=expi<1000)。
第三行输入一个正整数M(0<M<=500),代表链表B中结点的个数。
第四行输入2M个整数,输入的形式为 coffi expi, 代表每一项的系数和指数,输入保证对于任意 i≠j, coffi≠coffj ( 0<|coffi|<1000 , 0<=expi<1000)。
输出
输出包括一行, 即按照指数降序输出AB的结果,系数为零的项不能输出。 若AB的结果为空,输出 “0 0”。
样例输入
3
2 1 2 4 3 2
2
4 3 2 4
样例输出
4 8 8 7 6 6 16 5 8 4
#include<bits/stdc++.h>//有点bug
using namespace std;
//利用二重循环实现乘法,并将指数相同的项进行合并
typedef struct ListNode{
int val,ex;//分别为系数和指数
ListNode* next;
ListNode(int v,int e):val(v),ex(e),next(NULL){}
}ListNode,*Polynomial;
void display(Polynomial h){//多项式h存储的时候是从小到大存储,然后利用递归实现从大到小输出
if(!h) return;
display(h->next);
if(h->ex!=-1) printf("%d %d ",h->val,h->ex);
}
Polynomial CreatePoly()
{
Polynomial L = new ListNode(-1,-1),r=L;
int n,v,e;
cin>>n;
while(n--){
cin>>v>>e;
r->next=new ListNode(v,e);
r=r->next;
}
r->next=NULL;//处理最后一个结点
return L;
}
Polynomial mutiple(Polynomial h1,Polynomial h2){//多项式相乘,返回结果
Polynomial h = new ListNode(-1,-1),p=h1->next,q=h2->next,r,s;
int VAL,EX;
for(;p;p=p->next){
for(q=h1->next;q;q=q->next){//从h2的头节点开始
VAL=p->val*q->val;
EX=p->ex+q->ex;
r=h;
while(r->next&&EX>r->next->ex) r=r->next;
if(!r->next||r->next->ex>EX){//如果到达链表尾部或者链表中没有该指数结点
s = new ListNode(0,0);
s->ex=EX;
s->val=VAL;
s->next=r->next;//将新创建的结点插入到r后面
r->next=s;
}else if((r->next->ex==EX)&&(r->next->val+VAL==0)){//若找到指数一样的结点,且系数相互抵消后,直接删除该节点
s = r->next;
r->next=s->next;
delete s;
}else if((r->next->ex==EX)&&(r->next->val+VAL!=0)){//若找到指数一样的结点,且系数不抵消
r->next->val+=VAL;//系数相加
}
}
}
return h;
}
int main()
{
Polynomial h1=CreatePoly();
Polynomial h2=CreatePoly();
Polynomial h=mutiple(h1,h2);
if(!h)
printf("0 0");
else
display(h);
return 0;
}
1010: 好坑的电子地图(迪杰斯特拉)
题目描述
小明是今年参加复试的外校考生,他要去民主楼小礼堂签到。由于对中南大学校本部很不熟悉,小明找到了这边读书的好朋友鲁大师,不巧,鲁大师在忙着自由探索项目的结题工作,不能给他带路,只好给他发了一份半成品的电子地图。地图上只列出了校本部内的N个点,M条路,小明处于S点,民主楼小礼堂是T点。小明感谢鲁大师,当然只是在拿到地图的一瞬间,后面的情况让他知道这半成品到底有多坑。鲁大师制作的电子地图是带有语音提示功能的,但是在编号为奇数的点他要等1分钟才能告诉他具体怎么走,而在编号为偶数的点要等2分钟。现在告诉你地图的具体情况,小明想知道他能不能在A分钟内赶到民主楼小礼堂。
输入
输入数据有多组,每组占M+1行,第一行有5个数字N,M,S,T,A,接下来M行,每行三个数字u,v,t,代表每条路的两个顶点和步行时间。(输入数据保证不含重边0<N<M<1000)
输出
对于每组输入数据,输出一行,小明能在A分钟内赶到民主楼小礼堂输出YES和最少花费的时间,否则输出KENG
样例输入
4 3 1 4 10
1 2 1
3 2 2
3 4 3
5 4 2 4 7
1 2 5
5 4 2
3 5 1
2 3 1
样例输出
YES 10
KENG
#include<bits/stdc++.h>
using namespace std;
//常规的最短路径问题,唯一需要注意的是,在奇数点需要等待1分钟,偶数点等待2分钟
//处理方式就是在奇数点出发的边权全部+1,偶数点全部+2
int n,m,s,t,total;
int mp[1010][1010],dis[1010];
int vis[1010];
const int INF =1e9+7;
void init()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) mp[i][j]=0;
else mp[i][j]=INF;
}
}
}
void Dijtra()
{
for(int i=1;i<=n;i++)
dis[i]=mp[s][i];
vis[s]=1;
for(int i=1;i<=n-1;i++){
int minn=INF,minid;
for(int j=1;j<=n;j++){//把dis中最小的选出
if(!vis[j]&&minn>dis[j]){
minn=dis[j];
minid=j;
}
}
vis[minid]=1;//选出最小节点标记
for(int j=1;j<=n;j++){//用选出的节点作为中间节点更新dis
if(!vis[j]&&dis[j]>dis[minid]+mp[minid][j]){
dis[j]=dis[minid]+mp[minid][j];
}
}
}
if(dis[t]<=total)
printf("YES %d\n",dis[t]);
else
printf("KENG\n");
}
int main()
{
while(cin>>n>>m>>s>>t>>total){
init();
for(int i=0;i<m;i++){
int u,v,c;
cin>>u>>v>>c;
if(u%2==1) mp[u][v]=c+1;//奇数点时间+1
else mp[u][v]=c+2;
if(v%2==1) mp[v][u]=c+1;
else mp[v][u]=c+2;
}
Dijtra();
}
return 0;
}
1393: 国防部长PIPI (Kruskal)
题目描述
PIPI国有n个哨所,每个哨所都配置了一台型号相同的无线电通讯设备。设备有一个通讯半径D,如果两个哨站距离超过D,就无法直接通讯。
无线电通讯设备功率越高,通讯半径就越大,但是造价也就越高。为了省钱,PIPI需要确定一个最小的通讯半径D,所有的哨站使用这一型号设备后,任意两个哨站都能进行通讯(直接或间接)。
输入
多组测试用例
第一行为整数n,表示哨所的数目。2<=n<=100。
接下来n行,每行给出一个坐标(x,y),表示第i个哨所的坐标。-50000<=x,y<=50000.
输出
每组数据输出一个实数,表示D的最小值。保留两位小数。
样例输入
4
0 100
0 300
0 600
150 750
样例输出
300.00
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pr;
const int M=1e4+5;
struct Edge{
int x,y;
double d;
}E[M];
pr point[105];
int f[105];
int cmp(Edge a,Edge b)
{
return a.d<b.d;
}
int find_f(int x)
{
return f[x]==x?x:f[x]=find_f(f[x]);
}
int main()
{
int n;
while(cin>>n){
int id=0;
for(int i=1;i<=n;i++)
cin>>point[i].first>>point[i].second,f[i]=i;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
double r=sqrt((point[i].first-point[j].first)*(point[i].first-point[j].first)+(point[i].second-point[j].second)*(point[i].second-point[j].second));//pow(2,(point[i].first-point[j].first))+pow(2,(point[i].second-point[j].second));
E[id++]={i,j,r};
//cout<<r<<endl;
}
}
sort(E,E+id,cmp);
double ans=0;
for(int i=0;i<id;i++){//将一条条边加入
int fa=find_f(E[i].x),fb=find_f(E[i].y);
//cout<<E[i].d<<endl;
if(fa!=fb){
f[fa]=fb;
ans=E[i].d;
}
}
printf("%.2f\n",ans);
}
return 0;
}
1282: 数组中的第K个最大元素(快排思想)
题目描述
在数组中找到从小到大排序后第k大的元素。
输入
第一行输入数组长度n(n<=10000) 和 k.
第二行输入n个数字。
输出
输出数组中第k个最大的元素。
样例输入
6 2
3 2 1 5 6 4
样例输出
5
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int nums[N];
int Partition(int *nums,int low,int high)
{
int povit=nums[low];
while(low<high){
while(low<high&&povit<=nums[high]) high--;
nums[low]=nums[high];
while(low<high&&povit>=nums[low]) low++;
nums[high]=nums[low];
}
nums[low]=povit;
return low;
}
int findk(int *nums,int low,int high,int k){
int index=Partition(nums,low,high);
if(index==k)//如果中枢正好是第k大元素,返回
return nums[index];
else if(index<k)//中枢元素小于第k大元素,在中枢右边找
return findk(nums,index+1,high,k);
else//中枢元素大于第k大元素,在中枢左边找
return findk(nums,low,index-1,k);
}
int main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>nums[i];
}
printf("%d\n",findk(nums,1,n,n-k+1));//注意这里是第k大,所以要n-k+1
return 0;
}
1360: 删除最外层括号(栈)
题目描述
有效的括号字符串有 () , (A) , A+B, 其中A,B也为有效的括号字符串。若有效的括号字符串S非空,且不存在将S分解为A+B的方法(A,B皆为有效的括号字符串),那么S为不可分解的。给出字符串S,我们将其分解为 S = S1+S2+…+Sn, 其中每一个Si都是不可分解的。
现在要求你将S拆分为n个不可分解的串,并去除掉每一个不可分解串最外层的括号。
输入
输入包含多组测试样例。
每一组测试样例都是一个合法字符串S (|S|<100)。
输出
对于每组样例,输出分解之后然后去除掉括号的字符串。
样例输入
(()())(())
()(())
样例输出
()()()
()
#include<bits/stdc++.h>
using namespace std;
stack<char> st;
string ans;
void solve(string s)//输入的括号串是合法的
{
ans="";
for(int i=0;i<s.size();i++){
if(s[i]=='('){
if(!st.empty())//如果为’(’,而且栈里有左括号了,那整个左括号不能分解了
ans+=s[i];
st.push(s[i]);
}else{
st.pop();
if(!st.empty())//如果为右括号,而且不是最外层的右括号,加入
ans+=s[i];
}
//cout<<ans<<endl;
}
}
int main()
{
string s;
while(cin>>s){
solve(s);
cout<<ans<<endl;
}
return 0;
}
1407: 八大排序——基数排序
题目描述
请使用基数排序对题中给出的数据进行排序。
输入
输入的第一行包含1个正整数n,表示共有n个整数需要参与排序。其中n不超过100000。
第二行包含n个用空格隔开的正整数,表示n个需要排序的整数。
输出
只有1行,包含n个整数,表示从小到大排序完毕的所有整数。
请在每个整数后输出一个空格,并请注意行尾输出换行。
样例输入
10
2 8 4 6 1 10 7 3 5 9
样例输出
1 2 3 4 5 6 7 8 9 10
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N=1e5+5;
int D; //最大位数
//获取整数的第i位数u
int GetDigit(int x,int i){
while(i>1){
x/=10;
i--;
}
return x%10;
}
//基数排序
void RadixSort(int *num,int len)
{
int k,l,digit;
int allot[10][len];
int vis[10];
//初始化为0
memset(allot,0,sizeof(allot));
for(int i=1;i<=D;i++){
memset(vis,0,sizeof(vis));
//将每个数据的第i位分配到allot数组中
for(int j=0;j<len;j++){
//获取当前数据的第 j 位
digit=GetDigit(num[j],i);
k=0;
//查找插入的位置
/*while(allot[digit][k])
k++;*/
//放入allot[digit]末尾
allot[digit][vis[digit]]=num[j];
vis[digit]++;
}
//将分配数组的数据放到原数组中
l=0;
for(int j=0;j<10;j++){
k=0;
while(allot[j][k])
num[l++]=allot[j][k++];
}
memset(allot,0,sizeof(allot));
}
}
int main()
{
int n;
cin>>n;
int num[N];
int M=-INF;
for(int i=0;i<n;i++){
scanf("%d",&num[i]);
M=max(M,num[i]);
}
D=0;
while(M){
D++;
M/=10;
}
RadixSort(num,n);
for(int i=0;i<n;i++)
printf("%d ",num[i]);
printf("\n");
return 0;
}
1292: 中缀表达式转后缀表达式II
PIPI现在有若干个包含小写英文字母作为操作数 以及 ‘+’, ‘-’, ‘*’, ‘/’, ‘^’ ,‘(’,')‘七种操作符的合法中缀表达式。请你将其转为后缀表达式(逆波兰式)。
PS:’'代表幂运算,23=8
输入
输入一个字符串s,表示中缀表达式。
输出
输出一个字符串表示对应的后缀表达式。
样例输入
a+b*c+(d*e+f)*g
样例输出
abc*+de*f+g*+
#include<bits/stdc++.h>
using namespace std;
int main()
{
int v[300];//定义操作符的优先级
v['(']=0,v['+']=v['-']=1,v['*']=v['/']=2,v['^']=3;
string s;
cin>>s;
stack<char> st;
for(int i=0;i<s.size();i++){
if(s[i]>='a'&&s[i]<='z')
cout<<s[i];
else if(s[i]=='(')//若是左括号直接入栈
st.push(s[i]);
else if(s[i]==')')//若是右括号直接输出栈内元素,直到出栈到左括号
{
while(st.top()!='('){
cout<<st.top();
st.pop();
}
st.pop();//把左括号出栈
}
else{
//若是操作符且该操作符优先级小于等于栈顶操作符优先级
//输出栈顶元素,直到栈为空或者该操作符优先级比栈顶操作优先级高
while(!st.empty()&&v[s[i]]<=v[st.top()]){
cout<<st.top();
st.pop();
}
st.push(s[i]);
}
}
while(!st.empty()){//输出栈内剩余元素
cout<<st.top();
st.pop();
}
cout<<endl;
return 0;
}
1311: 删除最少无效括号
题目描述
给你一个仅由 ‘(’、‘)’ 组成的字符串 s。
你需要从字符串中删除最少数目的 ‘(’ 或者 ‘)’ (可以删除任意位置的括号),使得剩下的括号字符串合法。
输入
输入包含一个字符串s , 长度不超过 1e5
输出
输出包含最长的合法字符串。
样例输入
(()))(())((()
样例输出
(())(())()
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int main()
{
string s;
cin>>s;
stack<int> st;
int forbid[N];//标记需要删除括号的位置
memset(forbid,0,sizeof(forbid));
for(int i=0;i<s.size();i++){
if(s[i]=='(')
st.push(i);
else{
if(st.empty())//如果为右括号,且栈为空,说明右括号不合法
forbid[i]=1;
else
st.pop();//栈不为空,匹配成功
}
}
while(!st.empty()){
forbid[st.top()]=1;
st.pop();
}
for(int i=0;i<s.size();i++){
if(!forbid[i])
cout<<s[i];
}
return 0;
}
1332: 反转括号之间的子串
题目描述
PIPI有一个字符串s , 请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串。(PS: 串中每个左括号都有相应的右括号进行配对)
输入
输入包含多组测试用例。
第一行输入字符串 s ,s的长度不会超过100。
输出
对于每组测试用例,输出反转后的字符串(字符串中不包含任何括号)。
样例输入
(((jo))ipip)
(((jo))(pi)ip)
样例输出
pipioj
pipioj
#include<bits/stdc++.h>
using namespace std;
//遇到左括号,则将做左括号对应的下标压入栈
//遇到右括号,将栈中对应左括号的下标出栈,然后翻转这一段字符串
int main()
{
string s;
while(cin>>s){
stack<int> st;
for(int i=0;i<s.size();i++){
if(s[i]=='(')
st.push(i);
else if(s[i]==')'){
int l=st.top();st.pop();
int r=i;
reverse(s.begin()+l,s.begin()+r+1);
}
}
string ans;
for(int i=0;i<s.size();i++){
if(s[i]!='('&&s[i]!=')')
ans+=s[i];
}
cout<<ans<<endl;
}
return 0;
}
1368: 简单模式匹配算法
题目描述
给你两个字符串A与B,请问B是否作为子串在A中出现过?
字符串所有字符均由小写字母组成。
输入
第一行输出字符串A,|A|<=1000。
第二行输入字符串B,|B|<=1000。
输出
若B作为子串在A中出现过,输出YES,否则输出NO。
样例输入
abc
bc
样例输出
YES
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s1,s2;
cin>>s1>>s2;
int flag=0;
for(int i=0;i+s2.size()<=s1.size();i++){
for(int j=0,k=i;j<s2.size();j++,k++){
if(s1[k]!=s2[j])
break;
if(j==s2.size()-1)
flag=1;
}
if(flag==1) break;
}
if(flag)
printf("YES\n");
else
printf("NO\n");
return 0;
}
1269: 还原二叉树II(中序+后序->先序)
题目描述
PIPI现在有两个序列,分别为二叉树的中序序列和二叉树的后序序列,他想由这两个序列还原二叉树,你能帮PIPI还原吗?
输入
第一行输入序列的长度n (0<n<100).
第二行输入二叉树的中序序列。
第三行输入二叉树的后序序列。
输出
输出二叉树的先序遍历序列。
样例输入
3
2 1 3
2 3 1
样例输出
1 2 3
#include<bits/stdc++.h>
using namespace std;
const int MaxSize=100;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
};
int inorder[MaxSize],postorder[MaxSize];
TreeNode* build(int inorder[],int postorder[],int l1,int h1,int l2,int h2)
{
if(l1>h1) return NULL;
int llen,rlen,i;
TreeNode * root = new TreeNode;//后序遍历最后一个是根节点
root->val=postorder[h2];
for(i=l1;inorder[i]!=root->val;i++);
llen=i-l1;//左子树长度
rlen=h1-i;//右子树长度
root->left=build(inorder,postorder,l1,l1+llen-1,l2,l2+llen-1);//递归找左子树
root->right=build(inorder,postorder,h1-rlen+1,h1,h2-rlen,h2-1);//递归构造右子树
return root;
}
void Print(TreeNode * T){
if(T==NULL) return;
printf("%d ",T->val);
Print(T->left);
Print(T->right);
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>inorder[i];
for(int i=0;i<n;i++)
cin>>postorder[i];
TreeNode * T=build(inorder,postorder,0,n-1,0,n-1);
Print(T);
return 0;
}
1270: 还原二叉树III(二叉查找树+先序)
题目描述
PIPI现在知道了一棵二叉搜索树的先序序列,你能帮PIPI还原这棵二叉树吗?
输入
第一行输入序列的长度n (0<n<100).
第二行输入二叉树的先序序列。
输出
输出二叉树的后序遍历序列。
样例输入
6
8 5 1 7 10 12
样例输出
1 7 5 12 10 8
#include<bits/stdc++.h>
using namespace std;
const int MaxSize=100;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
};
//因为是二分查找树,所以中序遍历就是升序数组
int inorder[MaxSize],preorder[MaxSize];
TreeNode* build(int inorder[],int preorder[],int l1,int h1,int l2,int h2)
{
if(l1>h1) return NULL;
int llen,rlen,i;
TreeNode * root = new TreeNode;//后序遍历最后一个是根节点
root->val=preorder[l1];
for(i=l2;inorder[i]!=root->val;i++);
llen=i-l2;//左子树长度
rlen=h2-i;//右子树长度
root->left=build(inorder,preorder,l1+1,l1+llen,l2,l2+llen-1);//递归找左子树
root->right=build(inorder,preorder,h1-rlen+1,h1,h2-rlen+1,h2);//递归构造右子树
return root;
}
void Print(TreeNode * T){
if(T==NULL) return;
Print(T->left);
Print(T->right);
printf("%d ",T->val);
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>preorder[i],inorder[i]=preorder[i];
sort(inorder,inorder+n);
TreeNode * T=build(inorder,preorder,0,n-1,0,n-1);
Print(T);
return 0;
}
1263: 节点与其祖先之间的最大差值
题目描述
给定二叉树的根节点 root,找出存在于不同节点 A和 B 之间的最大值V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A72J7Fbo-1664854545110)(ipic/20190929211205_54979.jpg)]
输入
输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。
输出
输出一行代表最大差值V。
样例输入
8 3 1 -1 -1 6 4 -1 -1 7 -1 -1 10 -1 14 13 -1 -1 -1
样例输出
7
提示
样例输入即为题面的二叉树,最优选择是 |8-1| = 7
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int ans;//结点差
typedef struct node{
int w;
node *left,*right;
}node;
node *build(){//由先序遍历创建二叉树
int x;
cin>>x;
if(x==-1){
return NULL;
}
else{
node *root= new node;
root->w=x;
root->left=build();
root->right=build();
return root;
}
}
void find_ans(node *root,int Max,int Min)
{
if(root==NULL) return;
if(root->w>Max) Max=root->w;
if(root->w<Min) Min=root->w;
if(ans<Max-Min) ans=Max-Min;
find_ans(root->left,Max,Min);
find_ans(root->right,Max,Min);
}
int main()
{
node *root=build();
ans=0;
find_ans(root,-INF,INF);
cout<<ans<<endl;
return 0;
}
1264: 更大和树
题目描述
给出二叉搜索树的根节点,该二叉树的节点值各不相同,修改二叉树,使每个节点node 的新值等于原树中大于或等于 node.val 的值之和。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uOzJfe2H-1664854545114)(ipic/20190930223033_36038.png)]
输入
输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。
输出
输出更大和树的先序序列。
样例输入
4 1 0 -1 -1 2 -1 3 -1 -1 6 5 -1 -1 7 -1 8 -1 -1
样例输出
30 36 36 -1 -1 35 -1 33 -1 -1 21 26 -1 -1 15 -1 8 -1 -1
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct TreeNode {
int val;
TreeNode * left;
TreeNode * right;
};
int sum=0;//统计累加值,便于快速更改结点值
void DFS(TreeNode *root)
{
if(root==NULL) return;
DFS(root->right);//先遍历右边,因为是线索二叉树,右子树结点值大
sum+=root->val;
root->val=sum;
DFS(root->left);
}
void build(TreeNode * &T)
{
int x;
cin>>x;
if(x==-1){
T=NULL;
return;
}
else{
T=new TreeNode;
T->val=x;
T->left=T->right=NULL;
build(T->left);
build(T->right);
}
}
void Print(TreeNode * T){//先序遍历
if(T==NULL){
printf("-1 ");
return;
}
printf("%d ",T->val);
Print(T->left);
Print(T->right);
}
int main()
{
TreeNode *T=NULL;
build(T);
DFS(T);
Print(T);
return 0;
}
1310: 同构二叉树
题目描述
如果T1可以通过若干次左右孩子互换变成T2,则我们称两棵树是“同构”的。 例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cRhVxyrw-1664854545116)(ipic/20191206192628_49456.png)]
图一
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-joh224GU-1664854545118)(ipic/20191206192728_19233.png)]
图二
输入
第一行按照先序输入T1,其中空节点用 -1 表示。
第二行按照先序输入T2,其中空节点用 -1 表示。
输出
如果两棵树是同构的,也就说明麓石开盗窃了PIPI的资料,输出"YES"。否则输出"NO".
样例输入
1 2 4 -1 -1 5 6 -1 -1 -1 3 7 8 -1 -1 -1 -1
1 3 7 -1 8 -1 -1 -1 2 5 6 -1 -1 -1 4 -1 -1
样例输出
YES
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct TreeNode {
int val;
TreeNode * left;
TreeNode * right;
};
void build(TreeNode * &T)
{
int x;
cin>>x;
if(x==-1){
T=NULL;
return;
}
else{
T=new TreeNode;
T->val=x;
T->left=T->right=NULL;
build(T->left);
build(T->right);
}
}
bool issimilar(TreeNode *A,TreeNode *B)
{
if(!A&&!B) return true;//如果都为空,则同构
if(!A&&B || A&&!B || A->val!=B->val) return false;//如果一空一非空,或者当前结点值不同,则不同构
//如果左左子树同构,右右子树同构,或者一左一右同构,即同构
if(issimilar(A->left,B->left)&&issimilar(A->right,B->right)) return true;
if(issimilar(A->left,B->right)&&issimilar(A->left,B->right)) return true;
return false;//否则不同构
}
int main()
{
TreeNode *T=NULL,*T1=NULL;
build(T);
build(T1);
if(issimilar(T,T1))
printf("YES\n");
else
printf("NO\n");
return 0;
}
1301: 交换二叉树的左右子树
题目描述
给定一棵二叉树,交换二叉树的左右子树。
输入
输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。
输出
输出交换后的二叉树的先序序列,空节点无需输出。
样例输入
1 2 -1 -1 3 -1 -1
样例输出
1 3 2
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct TreeNode {
int val;
TreeNode * left;
TreeNode * right;
};
void build(TreeNode * &T)
{
int x;
cin>>x;
if(x==-1){
T=NULL;
return;
}
else{
T=new TreeNode;
T->val=x;
T->left=T->right=NULL;
build(T->left);
build(T->right);
}
}
void Print(TreeNode * T){//先序遍历
if(T==NULL) return;
printf("%d ",T->val);
Print(T->left);
Print(T->right);
}
void Exchange(TreeNode * &T){
if(T==NULL) return;
Exchange(T->left);
Exchange(T->right);
swap(T->left,T->right);//交换左右子树
}
int main()
{
TreeNode *T=NULL;
build(T);
Exchange(T);
Print(T);
return 0;
}
1293: 手性二叉树
题目描述
1
/ \
2 2
/ \ / \
3 4 4 3
1
/ \
2 2
/ \ / \
4 3 4 3
输入
输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。
输出
若该二叉树是手性二叉树,输出 “yes”, 否则输出"no"。
样例输入
1 2 3 -1 -1 4 -1 -1 2 4 -1 -1 3 -1 -1
样例输出
yes
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct TreeNode {
int val;
TreeNode * left;
TreeNode * right;
};
void build(TreeNode * &T)
{
int x;
cin>>x;
if(x==-1){
T=NULL;
return;
}
else{
T=new TreeNode;
T->val=x;
T->left=T->right=NULL;
build(T->left);
build(T->right);
}
}
void Print(TreeNode * T){//先序遍历
if(T==NULL) return;
printf("%d ",T->val);
Print(T->left);
Print(T->right);
}
bool symmetry(TreeNode *T1,TreeNode *T2)
{
if(!T1&&!T2) return true;//全部为空,则为对称
if(!T1 || !T2) return false;//一颗为空,一颗不为空
if(T1->val!=T2->val) return false;
//T1的左子树和T2的右子树相等,T1的右子树和T2的左子树相等
return symmetry(T1->left,T2->right)&&symmetry(T1->right,T2->left);
}
int main()
{
TreeNode *T=NULL;
build(T);
if(symmetry(T,T))
printf("yes\n");
else
printf("no\n");
return 0;
}
1297: 树中节点的祖先
题目描述
PIPI有一棵结点值均不相同的二叉树,现在他想知道某结点的祖先结点有哪些,你能帮PIPI解决这个问题吗?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lezGXUuU-1664854545120)(ipic/20191114105918_42188.jpg)]
比如说值为13的结点的祖先为 8 10 14
输入
第一行按照先序输入一棵二叉树,其中空节点用 -1 表示。
第二行输入待查询结点的值。
输出
输出一行,代表该结点的祖先节点,从根节点开始输出。若树中无该结点,输出"No Node!"。若树中某结点无祖先,输出 “No Ancestor!”
样例输入
8 3 1 -1 -1 6 4 -1 -1 7 -1 -1 10 -1 14 13 -1 -1 -1
13
样例输出
8 10 14
法一:非递归方法
#include<bits/stdc++.h>
using namespace std;
const int N=100;
//利用栈去存储后序遍历过程中的结点,然后进行打印输出
struct TreeNode {
int val;
TreeNode *left,*right;
};
typedef struct {
TreeNode *t;
int tag;// tag为 0 代表左子树被访问,为 1 代表右子树别访问
}Stack;
Stack s[N];
void PostOrder(TreeNode *T,int x){
TreeNode *p=T;
int top=0;
while(p||top>0){
while(p&&p->val!=x){//一直沿左分支向下
top++;
s[top].t=p;
s[top].tag=0;
p=p->left;
}
if(p&&p->val==x){ //如果找到结点x,打印所有祖先结点
for(int i=1;i<=top;i++)
printf("%d ",s[i].t->val);
if(top<1)// 结点x就是根结点
printf("No Ancestor!\n");
return;
}
while(top>0 && s[top].tag==1)// 该节点的左右子树都已访问,访问根结点
top--;
//这两者顺序不可调换,否则会漏掉祖先结点
if(top>0){// 在该结点的左子树未找到x,访问该节点的右子树
s[top].tag=1;
p=s[top].t->right;
}
}
printf("No Node!\n");
}
void build(TreeNode * &T)
{
int x;
cin>>x;
if(x==-1){
T==NULL;
return ;
}
T=new TreeNode;
T->val=x;
T->left=T->right=NULL;
build(T->left);
build(T->right);
}
int main()
{
TreeNode * T=NULL;
build(T);
int x;
cin>>x;
PostOrder(T,x);
return 0;
}
法二:递归方法
#include<bits/stdc++.h>
using namespace std;
const int N=100;
//利用栈去存储后序遍历过程中的结点,然后进行打印输出
struct TreeNode {
int val;
TreeNode *left,*right;
};
int flag=0;//标记是否找到结点x
int s[200],x;
void Find_x(TreeNode * T,int n)//n表示T结点前面已经有n个祖先了
{
//如果该节点为空,或者已经找到了x结点,停止遍历
if(flag||!T) return ;
//如果为x结点
if(T->val==x){
flag=1;
//如果S中没有元素,表示该结点没有祖先
if(!n)
printf("No Ancestor!");
//否则输出其祖先结点
else{
for(int i=0;i<n;i++)
printf("%d ",s[i]);
}
return;
}
else//若该节点不是x结点,将其存在s中
s[n]=T->val;
Find_x(T->left,n+1);
Find_x(T->right,n+1);
}
void build(TreeNode * &T)
{
int x;
cin>>x;
if(x==-1){
T==NULL;
return ;
}
T=new TreeNode;
T->val=x;
T->left=T->right=NULL;
build(T->left);
build(T->right);
}
int main()
{
TreeNode * T=NULL;
build(T);
cin>>x;
Find_x(T,0);
if(!flag)
printf("No Node!");
return 0;
}
1302: PIPI的族谱(判断两个结点是否是兄弟还是堂兄弟)
题目描述
PIPI最近在看家里的族谱,发现族谱刚好组成了一棵二叉树,现在PIPI想询问族谱中的两个结点是否为兄弟或者堂兄弟。
兄弟: 深度相同, 双亲节点相同(同一个结点不能是兄弟)。
堂兄弟: 深度相同,双亲节点不同。
输入
第一行按照先序输入族谱代表的二叉树,其中空节点用 -1 表示。
第二行输入两个数字 x y,代表询问的两个结点的值。
输出
若询问的两个结点是兄弟,输出"brother" , 若询问的两个结点是堂兄弟,输出"cousin" ,否则输出"other relathionship"
(relationship写错了 , 请同学们直接复制"other relathionship")
样例输入
1 2 -1 4 -1 -1 3 -1 5 -1 -1
4 5
样例输出
cousin
#include<bits/stdc++.h>
using namespace std;
const int N=100;
//利用栈去存储后序遍历过程中的结点,然后进行打印输出
struct TreeNode {
int val;
TreeNode *left,*right;
};
int flag=0;//标记是否a,b为兄弟结点
void build(TreeNode * &T)
{
int x;
cin>>x;
if(x==-1){
T==NULL;
return ;
}
T=new TreeNode;
T->val=x;
T->left=T->right=NULL;
build(T->left);
build(T->right);
}
int depth(TreeNode *T,int h,int x)
{
int l,r;//分别是x在左子树的深度和右子树的深度
if(!T) return 0;//在这边子树上没找到结点x
//找到返回深度
if(T->val==x) return h;
l=depth(T->left,h+1,x);
r=depth(T->right,h+1,x);
//左右子树肯定只有一边有结点x,另一边是返回0
return l?l:r;
}
void judge(TreeNode *T,int a,int b){
//若标志flag已经为1,或者该节点为空,停止遍历
if(flag||!T) return;
//若该节点的左右孩子正好是a,b结点,将flag置1
if(T->left&&T->right&&((T->left->val==a&&T->right->val==b)||(T->left->val==b&&T->right->val==a))){
flag=1;
return;
}
judge(T->left,a,b);
judge(T->right,a,b);
}
int main()
{
TreeNode * T=NULL;
build(T);
int a,b;
cin>>a>>b;
int da=depth(T,1,a);
int db=depth(T,1,b);
judge(T,a,b);//判断是否为兄弟
if(da==db){
if(flag)
printf("brother\n");
else
printf("cousin\n");
}
else
printf("other relathionship\n");
return 0;
}