编程之美大赛第三题 树上的三角形 .

时间限制: 2000ms 内存限制: 256MB

描述

有一棵树,树上有只毛毛虫。它在这棵树上生活了很久,对它的构造了如指掌。所以它在树上从来都是走最短路,不会绕路。它还还特别喜欢三角形,所以当它在树上爬来爬去的时候总会在想,如果把刚才爬过的那几根树枝/树干锯下来,能不能从中选三根出来拼成一个三角形呢?

输入

输入数据的第一行包含一个整数 T,表示数据组数。

接下来有 T 组数据,每组数据中:

第一行包含一个整数 N,表示树上节点的个数(从 1 到 N 标号)。

接下来的 N-1 行包含三个整数 a, b, len,表示有一根长度为 len 的树枝/树干在节点 a 和节点 b 之间。

接下来一行包含一个整数 M,表示询问数。

接下来M行每行两个整数 S, T,表示毛毛虫从 S 爬行到了 T,询问这段路程中的树枝/树干是否能拼成三角形。

输出

对于每组数据,先输出一行"Case #X:",其中X为数据组数编号,从 1 开始。

接下来对于每个询问输出一行,包含"Yes"或“No”,表示是否可以拼成三角形。

数据范围

1 ≤ T ≤ 5

小数据:1 ≤ N ≤ 100, 1 ≤ M ≤ 100, 1 ≤ len ≤ 10000

大数据:1 ≤ N ≤ 100000, 1 ≤ M ≤ 100000, 1 ≤ len ≤ 1000000000

样例输入
2
5
1 2 5
1 3 20
2 4 30
4 5 15
2
3 4
3 5
5
1 4 32
2 3 100
3 5 45
4 5 60
2
1 4
1 3
样例输出
Case #1:
No
Yes
Case #2:
No
Yes
之前的想法很简单,求出最短路径(Floyd算法),然后穷举,代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>

using namespace std;

#define ISTRIANGLE(a,b,c) (((a)+(b))>(c))&&(((a)+(c))>(b))&&(((c)+(b))>(a))?1:0
#define MAX 32767
vector<int> ivec;

class treeTriangle{
public:
	treeTriangle(int cases)
	{
		this->cases = cases;
	}
	void solution()
	{
		int iter;
        for(iter=1;iter<=cases;iter++){
			int i,j,k;
			int n;
			cin>>n;
			int **weight1 = new int*[n+1];
			int **weight2 = new int*[n+1];
			int **path = new int*[n+1];
			for(i=0;i<=n;i++)weight1[i]=new int[n+1];
			for(i=0;i<=n;i++)weight2[i]=new int[n+1];
			for(i=0;i<=n;i++)path[i]=new int[n+1];		
			for(i=0;i<=n;i++)//权数组的初始化
				//memset(weight[i],MAX,n+1);
				//memset(path[i],0,n+1);
				for(j=0;j<=n;j++){		
                   weight1[i][j] = MAX;
				   weight2[i][j] = MAX;
				   path[i][j] = 0;	  
				}
			for(i=0;i<=n;i++){
				weight1[i][i]=0;
				weight2[i][i]=0;
			}

			for(i=0;i<n-1;i++){//输入各边的权
				int vstart,vend,w;//因为是无向图所以有如下赋值
				cin>>vstart>>vend>>w;
				weight1[vstart][vend] = w;
				weight1[vend][vstart] = w;
				weight2[vstart][vend] = w;
				weight2[vend][vstart] = w;
				path[vstart][vend] = vstart;
				path[vend][vstart] = vend;
			}
			//floyd求两点之间的最短路径
			for(k=1;k<=n;k++)
				for(i=1;i<=n;i++)
					for(j=1;j<=n;j++){
						if(weight2[i][k]+weight2[k][j]<weight2[i][j]){
							weight2[i][j] = weight2[i][k]+weight2[k][j];
							path[i][j]=path[k][j];
						}
					}
			//求指点两点之前的路径
			int m;
			cin>>m;
			vector<bool> result;
			for(i=0;i<m;i++){
				vector<int> shortpath;
				int start,end;
				cin>>start>>end;
				while(path[start][end]!=start){
					shortpath.push_back(weight1[path[start][end]][end]);
					end = path[start][end];
				}
				shortpath.push_back(weight1[start][end]);
				int ii,jj,kk;
				bool res = false;
				if(shortpath.size()<3)goto R;
				for(ii=0;ii!=shortpath.size()-2;ii++)
					for(jj=1;jj!=shortpath.size()-1;jj++)
						for(kk=2;kk!=shortpath.size();kk++){
							if(ISTRIANGLE(shortpath[ii],shortpath[jj],shortpath[kk])){
					            res = true;
							    goto R;
							}
						}
                R:result.push_back(res);
			}
			cout<<"Case #"<<iter<<":"<<endl;
			for(i=0;i!=result.size();i++){
				if(result[i])  cout<<"Yes"<<endl;
				else cout<<"No"<<endl;
			}

			for(i=0;i<n;i++){
				delete[] weight1[i];
				delete[] weight2[i];
				delete[] path[i];
			}
			delete[] weight1;
			delete[] weight2;
			delete[] path;
			
		}
	}
private:
	int cases;
};


int main()
{
	int cases;
	cin>>cases;
    treeTriangle microsoft(cases);
	microsoft.solution();
	//system("pause");
	return 0;
}

后来发现,如果是一棵树,则两点之间肯定只有一个路径,可以不这么复杂。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值