2013编程之美 资格赛 树上的三角形

0.00 avg. rating (0% score) - 0 votes
转载请注明: 吹水小镇 | reetsee.com
原文链接地址: http://blog.reetsee.com/archives/22

题目描述:

时间限制: 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;
}

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注