与三角形三边有关的几个题

1.BOJ 320 

求一个数组的有多少组任意三个数能够组成三角形

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,in[3100];
int sea(int l,int h,int num){
	int ans=l-1;
	while(l<=h){
		int mid=(l+h)>>1;
		if(in[mid]>=num)
			h=mid-1;
		else{
			l=mid+1;
			ans=mid;
		}
	}
	return ans;
}
int main(){
	int i,j,t,T;
	long long ans;
	scanf("%d",&T);
	for(t=1;t<=T;t++){
		scanf("%d",&n);
		for(i=1;i<=n;i++)
			scanf("%d",&in[i]);
		sort(in+1,in+n+1);
		ans=0;
		for(i=1;i<=n;i++)
			for(j=i+1;j<n;j++){
				ans+=sea(j+1,n,in[i]+in[j])-j;
			}
		printf("%lld\n",ans);
	}
}


2.POJ 2967

这题巨坑,得加读入优化才能过==

先O(n)扫描出最小的两个和最大的一个,判断是否全都可以;
否则,如果全部不可以的话,可以证明其最“密”的形式即为fibonacci数列,所以当n>m(Fm>2 000 000 000)时必有解。否则再排序。

根据题目的数据范围当n>50时必有解

#include <cstdio>    
#include <cstring>    
#include <algorithm>    
using namespace std;    
const int MAXN = 1000005;    
    
int n, a[MAXN];    
    
int readInteger()    
{    
    int res = 0;    
    char ch = getchar();    
    while(ch >= '0' && ch <= '9')    
    {    
        res = res * 10 + ch - '0';    
        ch = getchar();    
    }    
    return res;    
}    
    
bool judge(int a, int b, int c)    
{    
    return a > c - b;    
}    
    
bool judge()    
{    
    if(n <= 3)    
    {    
        return false;    
    }    
    if(judge(a[0], a[1], a[n-1]))    
    {    
        return false;    
    }    
    if(n>50) return 1;
    for(int i=2;i<n;++i)    
    {    
        if(judge(a[i-2], a[i-1], a[i]))    
        {    
            return true;    
        }    
    }    
    return false;    
}    
    
int main()    
{    
    n = readInteger();    
    for(int i=0;i<n;++i)    
        a[i] = readInteger();  
      
    sort(a, a + n);    
    if(judge())  
        printf("The set is accepted.\n");    
    else  
        printf("The set is rejected.\n");    
    return 0;    
}    


2013编程之美资格赛第三题 http://programming2013.cstnet.cn/qualification/problem/3

LCA+sort判断

下面代码参考别人的

LCA用tarjan去求

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=100000+5;

struct Node {
    int beg, fa,pre, h;
    vector<int>query;
} a[N];

struct Edge {
    int next, len, t;
} e[N<<1];

struct Query {
    int x, y, ans;
} q[N];
int n, M, m;
bool vis[N];
int fa[N];

int find(int u) {
    int v=fa[u];
    while (v!=fa[v])v=fa[v];
    return fa[u]=v;
}

int init(int n) {
    M=1;
    for (int i=1; i<=n; i++) {
        //开始边
        a[i].beg=0;
        //父亲编号
        a[i].fa=i;
        //深度
        a[i].h=0;
        //相关查询
        a[i].query.clear();
        //是否在tarjan中处理过
        vis[i]=false;
        //tarjan并查集
        fa[i]=i;
    }
}

//添加一个条有向边
void add(int u, int v, int w) {
    e[++M].t=v;
    e[M].len=w;
    e[M].next=a[u].beg;
    a[u].beg=M;
}
//开始建树
int build(int u) {
    //枚举相连的点
    for (int cur=a[u].beg, v; v=e[cur].t, cur; cur=e[cur].next)
        //非父亲节点
        if (v!=a[u].fa) {
            //设置为父亲节点
            a[v].fa=u;
            //与父亲节点的距离
            a[v].pre=e[cur].len;
            //深度+1
            a[v].h=a[u].h+1;
            //递归建树
            build(v);
        }
}

//tarjan求树上两点公共祖先
int solve(int u) {
    //已访问
    vis[u]=true;
    //自成集合
    fa[u]=u;
    //枚举该点相关的查询
    for (int i=0;i<a[u].query.size();i++){
        //另一个点
        int v=q[a[u].query[i]].x+q[a[u].query[i]].y-u;
        //如果已经访问过
        if (vis[v]){
            //得出两点的最近公共祖先
            q[a[u].query[i]].ans=find(v);
        }
    }
    //枚举子节点
    for (int cur=a[u].beg,v;v=e[cur].t,cur;cur=e[cur].next)
        if(v!=a[u].fa && !vis[v]){
            solve(v);
            //合并集合
            fa[v]=u;
        }
}

//回答问题
void answer(int i) {
    int x=q[i].x,y=q[i].y,z=q[i].ans;
    if(z<0){
        printf("No\n");
        return ;
    }
    //相隔超过50个边,一定满足要求
    if (a[x].h+a[y].h-2*a[z].h>=50){
        printf("Yes\n");
        return ;
    }
    //记录所有路程边
    vector<int>b;
    //x点到最近公共祖先z的路径
    while (x!=z){
        b.push_back(a[x].pre);
        x=a[x].fa;
    }
    //y点到最近公共祖先z的路径
    while (y!=z){
        b.push_back(a[y].pre);
        y=a[y].fa;
    }
    //排序
    sort(b.begin(),b.end());
    //判定是否有可构成三角形的
    for (int i=2;i<b.size();i++)
        if (b[i-2]+b[i-1]>b[i]){
            printf("Yes\n");
            return;
        }
    //没有符合要求的边
    printf("No\n");
    return ;
}
//展示节点记录a中的数据
void display_a(int i){
    printf("ID=%d,fa=%d,pre=%d,h=%d\n",i,a[i].fa,a[i].pre,a[i].h);
    for (int j=0;j<a[i].query.size();j++)
        printf("%d ",a[i].query[j]);
    printf("\n");
}
//展示查询记录q中的数据
void display_q(int i){
    printf("ID=%d,x=%d,y=%d,z=%d\n",i,q[i].x,q[i].y,q[i].ans);
}
int main() {
    int total, tt=0;
    //读入Case数
    cin>>total;
    while (total--) {
        //读入点数
        scanf("%d", &n);
        //初始化各个数组
        init(n);
        int u, v, w;
        //读入树上边数
        for (int i=1; i<n; i++) {
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
            add(v, u, w);
        }
        scanf("%d", &m);
        //读入查询
        for (int i=0; i<m; i++) {
            scanf("%d%d", &u, &v);
            q[i].x=u, q[i].y=v;
            q[i].ans=-1;
            //把查询编号记录在关联的点上
            a[u].query.push_back(i);
            a[v].query.push_back(i);
        }
        //以1为根节点建图
        build(1);
        //开始tarjan求查询点最近公共祖先
        solve(1);
        printf("Case #%d:\n", ++tt);
        //for (int i=1;i<=n;i++)display_a(i);
        //for (int i=0;i<m;i++)display_q(i);
        for (int i=0; i<m; i++) {
            //回答每个查询
            answer(i);
        }
    }
    return 0;
}
LCA用定义求法

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

struct edge{
    int v, len;
    edge(int _v, int _len):v(_v), len(_len){}
};
int T, N, M;
vector<edge> e[100005];
int p[100005], depth[100005], len[100005];
void dfs(int u, int f, int d, int l){
    p[u] = f, depth[u] = d, len[u] = l;
    for(int i = 0; i < e[u].size(); ++i){
        int v = e[u][i].v;
        if(v == f) continue;
        dfs(v, u, d + 1, e[u][i].len);
    }
}
int s[50];
bool query(int u, int v){
    int cnt = 0;
    while(u != v){
        if(depth[u] > depth[v]){
            s[cnt++] = len[u];
            u = p[u];
        }else if(depth[u] < depth[v]){
            s[cnt++] = len[v];
            v = p[v];
        }else{
            s[cnt++] = len[u];
            s[cnt++] = len[v];
            u = p[u];
            v = p[v];
        }
        if(cnt > 46) return true;
    }
    sort(s, s + cnt);
    for(int i = 2; i < cnt; ++i){
        if(s[i-2] + s[i-1] <= s[i]) continue;
        return true;
    }
    return false;
}
void solve(){
    scanf("%d", &N);
    for(int i = 1; i <= N; ++i) e[i].clear();
    for(int i = 1; i < N; ++i){
        int u, v, len;
        scanf("%d%d%d", &u, &v, &len);
        e[u].push_back(edge(v, len));
        e[v].push_back(edge(u, len));
    }
    dfs(1, 0, 0, 0);
    scanf("%d", &M);
    for(int i = 0; i < M; ++i){
        int u, v; scanf("%d%d", &u, &v);
        printf(query(u, v) ? "Yes\n" : "No\n");
    }
}

int main(int argc, char** argv) {
    scanf("%d", &T);
    int nCase = 1;
    while(nCase <= T){
        printf("Case #%d:\n", nCase++);
        solve();
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值