2016 Multi-University Training Contest 1题解报告

此文章可以使用目录功能哟↑(点击上方[+])

依旧是菜鸟的我,感觉做得很吃力,膜拜高中生...

链接→2016 Multi-University Training Contest 1

 Problem 1001 Abandoned country

Accept: 0    Submit: 0
Time Limit: 8000/4000 MS (Java/Others)    Memory Limit : 65536/65536K (Java/Others)

 Problem Description

An abandoned country has n(n≤100000) villages which are numbered from 1 to n. Since abandoned for a long time, the roads need to be re-built. There are m(m≤1000000) roads to be re-built, the length of each road is wi(wi≤1000000). Guaranteed that any two wi are different. The roads made all the villages connected directly or indirectly before destroyed. Every road will cost the same value of its length to rebuild. The king wants to use the minimum cost to make all the villages connected with each other directly or indirectly. After the roads are re-built, the king asks a men as messenger. The king will select any two different points as starting point or the destination with the same probability. Now the king asks you to tell him the minimum cost and the minimum expectations length the messenger will walk.

 Input

The first line contains an integer T(T≤10) which indicates the number of test cases. 

For each test case, the first line contains two integers n,m indicate the number of villages and the number of roads to be re-built. Next m lines, each line have three number i,j,wi, the length of a road connecting the village i and the village j is wi.

 Output

output the minimum cost and minimum Expectations with two decimal places. They separated by a space.

 Sample Input

1
4 6
1 2 1
2 3 2
3 4 3
4 1 4
1 3 5
2 4 6

 Sample Output

6 3.33

 Problem Idea

解题思路:

【题意】
n个村庄,m条双向路,任意两个存在两两可达,现在要从中选一些道路进行重建,使得花费最少(修复每条路的花费等于路的长度)

求最少花费是多少,此外,在此基础上,问最小期望为多少(期望=所有村庄中任意两个村庄距离之和/村庄对数)

【类型】
最小生成树prim+dfs

【分析】
这题,显然,要求最少花费,重建的路越少越好,但又要满足任意两个村庄可达,故可以考虑最小生成树。
kruscal的邻接表实现时间复杂度为O(eloge),而prim的邻接表实现时间复杂度为O(elogv),故本人选择prim。
然后求期望实际就是求树上任意两点距离之和的平均数问题,网上采用O(n)的dfs解决。

我们可以对每条边,求所有可能的路径经过此边的次数:设这条边两端的点数分别为A和B,那么这条边被经过的次数就是A*B,它对总的距离和的贡献就是(A*B*此边长度)。我们把所有边的贡献求总和,再除以总路径数N*(N-1)/2,即为最后所求。
每条边两端的点数的计算,实际上是可以用一次dfs解决的。任取一点为根,在dfs的过程中,对每个点k记录其子树包含的点数(包括其自身),设点数为a[k],则k的父亲一侧的点数即为N-a[k]。这个统计可以和遍历同时进行。故时间复杂度为O(n)。

【时间复杂度&&优化】
O(elogv)

题目链接→HDU 5723 Abandoned country

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct edge
{
    int v,to,x;
}e[2*N],w[M*2];
bool v[M];
int h[M],p,k,l[M];
__int64 n;
struct node
{
    int u,v,d;
    bool operator < (const node &a) const
    {
       return d>a.d;//最小值优先
    }
    node(){}
    node(int _u,int _v,int _d):u(_u),v(_v),d(_d){}
};
void add_edge(int u,int v,int x)
{
    e[p].v=v;
    e[p].x=x;
    e[p].to=h[u];
    h[u]=p++;
}
void add_newedge(int u,int v,int x)
{
    w[k].v=v;
    w[k].x=x;
    w[k].to=l[u];
    l[u]=k++;
}
double dp[M];
__int64 sum[M];
void dfs(int root,int father)
{
   sum[root]=1;
   for(int i=l[root];i+1;i=w[i].to)
    {
        int son=w[i].v;
        int len=w[i].x;
        if(son==father)
            continue;
        dfs(son,root);
        sum[root]+=sum[son];
        dp[root]+=dp[son]+(sum[son]*(n-sum[son]))*(double)len;
   }
}
int main()
{
    int t,i,m,a,b,c;
    __int64 ans;
    node u;
    priority_queue<node> q;
    scanf("%d",&t);
    while(t--)
    {
        k=p=0;ans=0;
        while(!q.empty())
            q.pop();
        scanf("%I64d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
            h[i]=-1;
            l[i]=-1;
            v[i]=false;
            sum[i]=0;
            dp[i]=0;
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            add_edge(b,a,c);
        }
        for(i=h[1];i+1;i=e[i].to)
            q.push(node(1,e[i].v,e[i].x));
        v[1]=true;
        while(!q.empty())
        {
            u=q.top();
            q.pop();
            if(v[u.v])
                continue;
            ans+=u.d;
            add_newedge(u.u,u.v,u.d);
            add_newedge(u.v,u.u,u.d);
            v[u.v]=true;
            for(i=h[u.v];i+1;i=e[i].to)
                if(!v[e[i].v])
                    q.push(node(u.v,e[i].v,e[i].x));
        }
        dfs(1,-1);
        __int64 s=(n*(n-1)/2);
        printf("%I64d %.2f\n",ans,dp[1]/s);
    }
    return 0;
}

 Problem 1002 Chess

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536K (Java/Others)

 Problem Description

Alice and Bob are playing a special chess game on an n × 20 chessboard. There are several chesses on the chessboard. They can move one chess in one turn. If there are no other chesses on the right adjacent block of the moved chess, move the chess to its right adjacent block. Otherwise, skip over these chesses and move to the right adjacent block of them. Two chesses can’t be placed at one block and no chess can be placed out of the chessboard. When someone can’t move any chess during his/her turn, he/she will lose the game. Alice always take the first turn. Both Alice and Bob will play the game with the best strategy. Alice wants to know if she can win the game.

 Input

Multiple test cases.

The first line contains an integer T(T≤100), indicates the number of test cases.

For each test case, the first line contains a single integer n(n≤1000), the number of lines of chessboard.

Then n lines, the first integer of ith line is m(m≤20), indicates the number of chesses on the ith line of the chessboard. Then m integers pj(1≤pj≤20) followed, the position of each chess.


 Output

For each test case, output one line of “YES” if Alice can win the game, “NO” otherwise.

 Sample Input

2
1
2 19 20
2
1 19
1 18

 Sample Output

NO
YES

 Problem Idea

解题思路:

【题意】
n×20
的棋盘,给你每行的棋子个数及位置,Alice和Bob轮流移动棋子,直至不能再移动棋子的人输

移动规则:每个棋子可以移动到其右边第一个空位,不能移出棋盘

【类型】
组合游戏博弈(SG函数)

【分析】
此题要用到SG函数,所以我们先大致讲解一下SG函数

SG函数表示的是某种局面的状态,它是由mex运算得到的

mex表示最小的不属于这个集合的非负整数,例如mex{0,1,2,4}=3,mex{2,3,5}=0,mex{}=0;

其实mex可以这么理解,0表示必败态,非零表示必胜态,根据定理"能一步到达必败态的点就是必胜态",故只有集合包含0,那么mex得到的数必定非0

根据定理"只能到达必胜态的点是必败态",故若集合中不包含0,那么mex得到的数必定为0

再回到该问题,我们采取状态压缩,把一行的棋盘状态压缩成一个二进制数串

比如下列棋盘

转换成二进制串为00000000000000101010->十进制数42

该状态经一步可以转变成三种状态,分别为00000000000000011010,00000000000000100110,00000000000000101001

我们只要知道这三种状态的SG值,那么当前状态的SG值就可以得到,继而知道当前为必胜态还是必败态


【时间复杂度&&优化】
O(20*2^20)

题目链接→HDU 5724 Chess

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 20;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
int sg[1<<N];
bool v[N];
int mex(int x)
{
    int i,k=-1;
    memset(v,false,sizeof(v));
    for(i=0;i<N;i++)
        if(!((1<<i)&x))
            k=i;
        else if(k!=-1)
            v[sg[x^(1<<k)^(1<<i)]]=true;
    for(i=0;i<N;i++)
        if(!v[i])
            return i;
}
int main()
{
    int t,i,j,n,m,p,s,ans;
    sg[0]=0;
    for(i=1;i<(1<<N);i++)
        sg[i]=mex(i);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(ans=i=0;i<n;i++)
        {
            scanf("%d",&m);
            for(s=j=0;j<m;j++)
            {
                scanf("%d",&p);
                s+=(1<<(N-p));
            }
            ans^=sg[s];
        }
        if(ans)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}


 Problem 1004 GCD

Accept: 0    Submit: 0
Time Limit: 10000/5000 MS (Java/Others)    Memory Limit : 65536/65536K (Java/Others)

 Problem Description

Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). There are Q(Q≤100,000) queries. For each query l,r you have to calculate gcd(al,al+1,...,ar) and count the number of pairs(l′,r′)(1≤l<r≤N)such that gcd(al′,al′+1,...,ar′) equal gcd(al,al+1,...,ar).

 Input

The first line of input contains a number T, which stands for the number of test cases you need to solve.

The first line of each case contains a number N, denoting the number of integers.

The second line contains N integers, a1,...,an(0<ai≤1000,000,000).

The third line contains a number Q, denoting the number of queries.

For the next Q lines, i-th line contains two number , stand for the li,ri, stand for the i-th queries.


 Output

For each case, you need to output “Case #:t” at the beginning.(with quotes, t means the number of the test case, begin from 1).

For each query, you need to output the two numbers in a line. The first number stands for gcd(al,al+1,...,ar) and the second number stands for the number of pairs(l′,r′) such that gcd(al′,al′+1,...,ar′) equal gcd(al,al+1,...,ar).

 Sample Input

1
5
1 2 4 6 7
4
1 5
2 4
3 4
4 4

 Sample Output

Case #1:
1 8
2 4
2 4
6 1

 Problem Idea

解题思路:

【题意】

t组数据,每组n个元素,q次询问,每次询问区间[l,r]内所有元素的最大公约数以及所有区间中有多少个区间的最大公约数与之相同

【类型】
线段树+map预处理

【分析】
此题有两问,我们不妨先解决第一个问题

首先,要求区间[l,r]内所有元素的最大公约数,因为有q次询问,所以我们不可能暴力求解,而是采用线段树

int gcd(int a,int b)
{
    if(a%b)
        return gcd(b,a%b);
    return b;
}
void push_up(int p)
{
    s[p].gcd=gcd(s[p*2].gcd,s[p*2+1].gcd);
}
void buildtree(int l,int r,int p)
{
    s[p].left=l;s[p].right=r;
    if(l==r)
    {
        s[p].gcd=a[l];
        return ;
    }
    int mid=(l+r)/2;
    buildtree(l,mid,p*2);
    buildtree(mid+1,r,p*2+1);
    push_up(p);
}
int query(int l,int r,int p)
{
    if(s[p].left==l&&s[p].right==r)
        return s[p].gcd;
    int mid=(s[p].left+s[p].right)/2;
    if(l>mid)
        return query(l,r,p*2+1);
    else if(r<=mid)
        return query(l,r,p*2);
    else
        return gcd(query(l,mid,p*2),query(mid+1,r,p*2+1));
}

其次,gcd相同的区间个数,这个必须预处理得到,不然每次重复计算必定超时

而要记录某gcd值所对应的区间个数,这个又是数组所不能完成的,故采用了map存储

对于以a[i]为右端点的所有区间=以a[i-1]为右端点的所有区间+区间[i,i],因为很多区间的gcd值是一样的,故而又可以合并,这一步就省去了很多时间



【时间复杂度&&优化】
O(nlognlogn)

题目链接→HDU 5726 GCD

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct node
{
    int left,right,gcd;
}s[4*N];
int a[N];
map<int,__int64> ans,m1,m2;//m1存储以s[i]作为右端点的所有区间的gcd及个数
map<int,__int64>::iterator it;
int gcd(int a,int b)
{
    if(a%b)
        return gcd(b,a%b);
    return b;
}
void push_up(int p)
{
    s[p].gcd=gcd(s[p*2].gcd,s[p*2+1].gcd);
}
void buildtree(int l,int r,int p)
{
    s[p].left=l;s[p].right=r;
    if(l==r)
    {
        s[p].gcd=a[l];
        return ;
    }
    int mid=(l+r)/2;
    buildtree(l,mid,p*2);
    buildtree(mid+1,r,p*2+1);
    push_up(p);
}
int query(int l,int r,int p)
{
    if(s[p].left==l&&s[p].right==r)
        return s[p].gcd;
    int mid=(s[p].left+s[p].right)/2;
    if(l>mid)
        return query(l,r,p*2+1);
    else if(r<=mid)
        return query(l,r,p*2);
    else
        return gcd(query(l,mid,p*2),query(mid+1,r,p*2+1));
}
int main()
{
    int t,n,i,k,q,l,r,g,p=1;
    scanf("%d",&t);
    while(t--)
    {
        ans.clear();
        m1.clear();
        m2.clear();
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        buildtree(1,n,1);
        for(i=1;i<=n;i++)
        {
            ans[a[i]]++;
            m2[a[i]]++;
            for(it=m1.begin();it!=m1.end();it++)
            {
                k=gcd(a[i],it->first);
                ans[k]+=it->second;
                m2[k]+=it->second;
            }
            m1.clear();
            m1=m2;
            m2.clear();
        }
        printf("Case #%d:\n",p++);
        scanf("%d",&q);
        for(i=0;i<q;i++)
        {
            scanf("%d%d",&l,&r);
            g=query(l,r,1);
            printf("%d %I64d\n",g,ans[g]);
        }
    }
    return 0;
}

 Problem 1005 Necklace

Accept: 0    Submit: 0
Time Limit: 3000/1500 MS (Java/Others)    Memory Limit : 65536/65536K (Java/Others)

 Problem Description

SJX has 2*N magic gems. N of them have Yin energy inside while others have Yang energy. SJX wants to make a necklace with these magic gems for his beloved BHB. To avoid making the necklace too Yin or too Yang, he must place these magic gems Yin after Yang and Yang after Yin, which means two adjacent gems must have different kind of energy. But he finds that some gems with Yang energy will become somber adjacent with some of the Yin gems and impact the value of the neckless. After trying multiple times, he finds out M rules of the gems. He wants to have a most valuable neckless which means the somber gems must be as less as possible. So he wonders how many gems with Yang energy will become somber if he make the necklace in the best way.

 Input

Multiple test cases.

For each test case, the first line contains two integers N(0≤N≤9),M(0≤M≤N∗N), descripted as above.

Then M lines followed, every line contains two integers X,Y, indicates that magic gem X with Yang energy will become somber adjacent with the magic gem Y with Yin energy.


 Output

One line per case, an integer indicates that how many gem will become somber at least.

 Sample Input

2 1
1 1
3 4
1 1
1 2
1 3
2 1

 Sample Output

1
1

 Problem Idea

解题思路:

【题意】
有2n颗阴阳宝珠,阴宝珠和阳宝珠各有n颗,它们交错编织成一条项链

现在告诉你某些阳宝珠和某些阴宝珠相邻会导致阳宝珠变得黯淡,问至少有几颗阳宝珠会变得黯淡


【类型】
枚举环排列+二分图匹配

【分析】
可以枚举一下阴宝珠的排列方式,因为是环,所以可以固定其中一个阴宝珠,剩下n-1个阴宝珠进行全排列。
对于每一个全排列,会产生n个位置供阳宝珠放置,如果在位置j放置阳宝珠i不会使该阳宝珠变得黯淡,则该阳宝珠i向该位置j连边。
然后跑一次二分图最大匹配,即可得到在阴宝珠当前的排列方式下,最多有多少阳宝珠不会褪色,更新一下答案即可。

另外,求全排列时,STL中有一个封装好了的函数next_permutation(begin,end),该函数能获得当前序列的下一个排列

与之对应的另一个函数prev_permutation(begin,end)则可以求当前序列的上一个排列


【时间复杂度&&优化】
O(n!·n^2)

题目链接→HDU 5727 Necklace

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 15;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
int l,r,link[N];//l为左集合点数,r为右集合点数
bool v[N],g[N][N];//编号为0~n-1
bool dfs(int u)
{
    int i;
    for(i=0;i<r;i++)
        if(g[u][i]&&!v[i])
        {
            v[i]=true;
            if(link[i]==-1||dfs(link[i]))
            {
                link[i]=u;
                return true;
            }
        }
    return false;
}
int hungary()
{
    int i,res=0;
    memset(link,-1,sizeof(link));
    for(i=0;i<l;i++)
    {
        memset(v,false,sizeof(v));
        if(dfs(i))
            res++;
    }
    return res;
}
bool Map[N][N];
int p[N];
int main()
{
    int n,m,i,j,a,b,ans;
    while(~scanf("%d%d",&n,&m))
    {
        if(!n)
        {
            puts("0");
            continue;
        }
        ans=inf;
        memset(Map,false,sizeof(Map));
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            Map[a-1][b-1]=true;
        }
        for(i=0;i<n;i++)
            p[i]=i;
        l=r=n;
        do
        {
            memset(g,false,sizeof(g));
            for(i=0;i<n;i++)
                for(j=0;j<n;j++)
                    if(!Map[i][p[j]]&&!Map[i][p[(j+1)%n]])
                        g[i][j]=true;
            ans=min(ans,n-hungary());
        }while(next_permutation(p+1,p+n)&&ans);
        printf("%d\n",ans);
    }
    return 0;
}


 Problem 1011 tetrahedron

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

Given four points ABCD, if ABCD is a tetrahedron, calculate the inscribed sphere of ABCD.

 Input

Multiple test cases (test cases ≤100).

Each test cases contains a line of 12 integers [−1e6,1e6] indicate the coordinates of four vertices of ABCD.

Input ends by EOF.

 Output

Print the coordinate of the center of the sphere and the radius, rounded to 4 decimal places.

If there is no such sphere, output "O O O O".

 Sample Input

0 0 0 2 0 0 0 0 2 0 2 0
0 0 0 2 0 0 3 0 0 4 0 0

 Sample Output

0.4226 0.4226 0.4226 0.4226
O O O O

 Problem Idea

解题思路:

【题意】
求解四面体的内切球的球心与半径。

【类型】
几何(判断四点共面)

【分析】
首先,既然题目说了有不存在的情况,那么我们就必须判断一下四点共面(即四个点构不成四面体)

判断是否为四面体的方法如下:

方法一:任取3个点,如果这三点共线,那么四点共面;如果这三点不共线,那么它们确定一个平面,考虑第四点到这个平面的距离.

方法二:A、B、C、D四点共面的充要条件为向量AB、AC、AD的混合积(AB,AC,AD)=0.

方法三:A、B、C、D四点不共面的充要条件为向量AB、AC、AD线性无关.

计算内切球半径的方法如下:

(S1+S2+S3+S4)*r = 3V
S1 ~ S4 是四面体的四个面积,内切球的半径为高,这样的4个体积加起来就是四面体的总体积.有点类似于三角形的内切圆半径的求法.
r = 3V / (S1+S2+S3+S4)

计算内切球球心的方法如下:

四面体的内心坐标公式及其应用

【时间复杂度&&优化】
O(1)

题目链接→HDU 5733 tetrahedron

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define bitnum(a) __builtin_popcount(a)
using namespace std;
#define zero(x) (((x)>0?(x):-(x))<eps)
const int N = 2;
const int M = 40;
const int inf = 1000000007;
const int mod = 1000000007;
struct point3
{
    double x,y,z;
}s[4];
//计算 dot product U .V
double dmult(point3 u,point3 v)
{
    return u.x*v.x+u.y*v.y+u.z*v.z;
}
//计算 cross product UxV
point3 xmult(point3 u,point3 v)
{
    point3 ret;
    ret.x=u.y*v.z-v.y*u.z;
    ret.y=u.z*v.x-u.x*v.z;
    ret.z=u.x*v.y-u.y*v.x;
    return ret;
}
point3 subt(point3 u,point3 v)
{//矢量差U-V
    point3 ret;
    ret.x=u.x-v.x;
    ret.y=u.y-v.y;
    ret.z=u.z-v.z;
    return ret;
}
point3 pvec(point3 s1,point3 s2,point3 s3)
{//取平面法向量
    return xmult(subt(s1,s2),subt(s2,s3));
}
bool dots_onplane(point3 a,point3 b,point3 c,point3 d)
{//判四点共面
    return zero(dmult(pvec(a,b,c),subt(d,a)));
}

double dist(point3 a,point3 b)
{
    double dx=a.x-b.x;
    double dy=a.y-b.y;
    double dz=a.z-b.z;
    double ans=fabs(sqrt(dx*dx+dy*dy+dz*dz));
    return ans;
}

double sq(point3 a,point3 b,point3 c)
{
    double l1=dist(a,b);
    double l2=dist(a,c);
    double l3=dist(b,c);
    double pp=(l1+l2+l3)/2;
    double ans=sqrt(pp*(pp-l1)*(pp-l2)*(pp-l3));
    return ans;
}

int main()
{
    while(~scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",&s[0].x,&s[0].y,&s[0].z,&s[1].x,&s[1].y,&s[1].z,&s[2].x,&s[2].y,&s[2].z,&s[3].x,&s[3].y,&s[3].z))
    {
        if(dots_onplane(s[0],s[1],s[2],s[3]))
            puts("O O O O");
        else
        {
            double v;
            v=(s[3].x-s[2].x)*(s[3].y-s[0].y)*(s[3].z-s[1].z)+(s[3].x-s[1].x)*(s[3].y-s[2].y)*(s[3].z-s[0].z)+(s[3].x-s[0].x)*(s[3].y-s[1].y)*(s[3].z-s[2].z)
            -(s[3].x-s[1].x)*(s[3].y-s[0].y)*(s[3].z-s[2].z)-(s[3].x-s[0].x)*(s[3].y-s[2].y)*(s[3].z-s[1].z)-(s[3].x-s[2].x)*(s[3].y-s[1].y)*(s[3].z-s[0].z);
            v/=2;
            v=fabs(v);
            double s3=sq(s[0],s[1],s[2]);
            double s0=sq(s[3],s[1],s[2]);
            double s1=sq(s[0],s[3],s[2]);
            double s2=sq(s[0],s[1],s[3]);
            double sqq=s1+s2+s3+s0;
            double xi,yi,zi;
            xi=s0*s[0].x+s1*s[1].x+s2*s[2].x+s3*s[3].x;
            yi=s0*s[0].y+s1*s[1].y+s2*s[2].y+s3*s[3].y;
            zi=s0*s[0].z+s1*s[1].z+s2*s[2].z+s3*s[3].z;
            printf("%.4f %.4f %.4f %.4f\n",xi/sqq,yi/sqq,zi/sqq,v/sqq);
        }
    }
    return 0;
}

菜鸟成长记

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 27
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值