题目描述:
时间限制: 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; }