题目描述:
时间限制: 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
解题思路:
我做这题的思路错了,以为路径是可带环的,其实是一棵树——我当时也考虑过这个问题不过题目说的树是虫子爬的树啊····所以我按照了解决有环以及可能出现多棵树的方法来做,用了SPFA算法,整个代码下来又长又臭,大家可以直接忽略我的代码,跳去“其它参考”这个地方,看下别人的代码好了。顺带讲一句,我的代码是针对小数据的····
注意:
那是一棵树
代码:
//代码适用于小数据
#include<iostream>
#include<queue>
#include<algorithm>
#include<memory.h>
using namespace std;
const int INF = 105*10000;
int mx[105][105];
int res[105][105];
int n,m;
bool inq[105];
int main()
{
int tc,cnt;
int tmpa,tmpb;
cin>>tc;
cnt= 0;
queue<int> q;
while(tc--)
{
memset(mx,0,sizeof(mx));
cout<<"Case #"<<++cnt<<":"<<endl;
cin>>n;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
res[i][j]=INF;
for(int i=0;i<n-1;++i)
{
cin>>tmpa>>tmpb;
cin>>mx[tmpa][tmpb];
mx[tmpb][tmpa]=mx[tmpa][tmpb];
}//记录节点距离
cin>>m;
while(m--)//计算query
{
int na,nb;
cin>>na>>nb;
if(res[na][nb]!=INF)
{
if(res[na][nb]==1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
continue;
}
//memset(inq,0,sizeof(inq));
int dis[105];//[105];
int las[105];
//for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
dis[j]=INF;
las[j]=INF;
}
//SPFA
q.push(na);
dis[na] = 0;
inq[na] = true;
while(!q.empty())
{
int u=q.front();//好像是先进的
q.pop();
inq[u]=false;
//int tmp = dis[u];
for(int i=1;i<=n;++i)
{
if(!mx[u][i])
continue;
//int tmp = dis[i];
//松弛操作
if(dis[i]>(dis[u]+mx[u][i]))
{
dis[i] = dis[u] + mx[u][i];
las[i] = u;
if(!inq[i])
{
inq[i]=true;
q.push(i);
}
}
}
}//处理完毕
if(dis[nb]==INF) //不连通
{
cout<<"No"<<endl;
res[nb][na] = res[na][nb] = 0;
}
else
{//连通
int edge[25];
int ct = 0;
int node = nb;
//edge[ct++] = las[nb];
int tt;
while(node!=na)
{
tt = ct-1;
edge[ct++] = mx[node][las[node]];//las[edge[tt]];
node = las[node];
if(ct>22)
break;
}
if(ct>22) //10000以内的斐波纳契数不超过22个
{
cout<<"Yes"<<endl;
res[nb][na] = res[na][nb] = 1;
}
else
{
sort(edge,edge+ct);
for(int i=2;i<ct;++i)
{
if((edge[i-2]+edge[i-1])>edge[i])
{
cout<<"Yes"<<endl;
res[nb][na] = res[na][nb] = 1;
break;
}
}
if(res[nb][na]!=1)
{
cout<<"No"<<endl;
res[nb][na] = res[na][nb] = 0;
}
}
}
}
}
}
其它参考:
//第三题来自mochavic
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
int deep[100010], f[100010][2];
vector<int> e[100010];
int c[60], cn;
void dfs(int fa, int x, int d){
int i, y;
deep[x] = d;
for (i = 0; i < (int)e[x].size(); i += 2){
y = e[x][i];
if (y == fa) continue;
f[y][0] = x;
f[y][1] = e[x][i + 1];
dfs(x, y, d + 1);
}
}
void pd(int x, int y){
while (deep[x] > deep[y]){
c[cn++] = f[x][1];
x = f[x][0];
if (cn == 50) return;
}
while (deep[y] > deep[x]){
c[cn++] = f[y][1];
y = f[y][0];
if (cn == 50) return;
}
while (x != y){
c[cn++] = f[x][1];
x = f[x][0];
c[cn++] = f[y][1];
y = f[y][0];
if (cn >= 50) return;
}
}
int main(){
int T, ri = 1, n, m, x, y, z, i;
scanf("%d", &T);
while (T--){
scanf("%d", &n);
for (i = 1; i <= n; i++) e[i].clear();
for (i = 1; i < n; i++){
scanf("%d%d%d", &x, &y, &z);
e[x].push_back(y);
e[x].push_back(z);
e[y].push_back(x);
e[y].push_back(z);
}
dfs(0, 1, 0);
printf("Case #%d:\n", ri++);
scanf("%d", &m);
while (m--){
scanf("%d%d", &x, &y);
cn = 0;
pd(x, y);
sort(c, c + cn);
for (i = 0; i + 2 < cn; i++){
if (c[i] + c[i + 1] > c[i + 2]) break;
}
if (i + 2 < cn) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}