题目列表 > 树上的三角形
时间限制: 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;
}
后来发现,如果是一棵树,则两点之间肯定只有一个路径,可以不这么复杂。