CSU-1848 3-sided dice(计算几何)

1848: 3-sided dice

            Time Limit: 1 Sec       Memory Limit: 128 Mb       Submitted: 42       Solved: 5    

Description

  Just like every fall, the organizers of the Southwestern Europe Dice Simulation Contest are busy again this year. In this edition you have to simulate a 3-sided die that outputs each of three possible outcomes (which will be denoted by 1; 2 and 3) with a given probability, using three dice in a given set. The simulation is performed this way: you choose one of the given dice at random, roll it, and report its outcome. You are free to choose the probabilities of rolling each of the given dice, as long as each probability is strictly greater than zero. Before distributing the mate- rials to the contestants, the organizers have to verify that it is actually possible to solve this task.

  For example, in the first test case of the sample input you have to simulate a die that yields outcome 1; 2 and 3 with probabilities  310,410 310,410 and  310 310 .We give you three dice, and in this case the i-th of them always yields outcome i, for each i = 1,2,3. Then it is possible to simulate the given die in the following fashion: roll the first die with probability  310 310 .the second one with probability  410 410 and the last one with probability  310 310 .

Input

  The input consists of several test cases, separated by single blank lines. Each test case consists of four lines: the first three of them describe the three dice you are given and the last one describes the die you have to simulate. Each of the four lines contains 3 space-separated integers between 0 and 10 000 inclusive. These numbers will add up to 10 000, and represent 10 000 times the probability that rolling the die described in that line yields outcome 1, 2 and 3, respectively.

  The test cases will finish with a line containing only the number zero repeated three times (also preceded with a blank line).

Output

  For each case, your program should output a line with the word YES if it is feasible to produce the desired die from the given ones, and NO otherwise.

Sample Input

0 0 10000
0 10000 0
10000 0 0
3000 4000 3000

0 0 10000
0 10000 0
3000 4000 3000
10000 0 0

0 0 0

Sample Output

YES
NO
题意:一个骰子有3面,每一面分别有权值Vi=(Xi,Yi,Zi)且Xi+Yi+Zi=10000,每一面朝上的概率0<Pi<1且P0+P1+P2=1,现在给出V3=(X3,Y3,Z3),问是否有(X3,Y3,Z3)=(∑Xi*Pi,∑Yi*Pi,∑Zi*Pi)

题解:把Vi考虑成三维坐标系下的向量

分情况讨论V3=P0*V0+P1*V1+P2*V2成立的条件:
①3个向量不共面:V3一定在其他3个向量组成的三角形中
②3个向量共面但向量不重合:V3一定在其他3个向量的端点所组成的线段中
③3个向量共面且有2个向量重合:V3一定在不重合的2个向量的端点所组中的线段中
④3个向量重合:V3=V0=V1=V2

对于情况①:用叉积计算出V0-V1-V2组成的三角形的面积,再计算出V0-V1-V3,V0-V2-V3,V1-V2-V3所组成的三角形面积之和,判断是否相等即可
计算面积的方法:2个向量的叉积等于其所围成的平行四边形的面积

对于情况②③:假如V3在V0和V1组成的线段中,那么向量V3-V0与向量V3-V1方向相反


#include<cstdio>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
using namespace std;
struct node{
    int x,y,z;
    node(){}
    node(int X,int Y,int Z){x=X;y=Y;z=Z;}
    bool operator==(const node P)const{
        return x==P.x&&y==P.y&&z==P.z;
    }
}p[5];
int Cross(int i,int j,int k){
    node v1(p[i].x-p[k].x,p[i].y-p[k].y,p[i].z-p[k].z),v2(p[j].x-p[k].x,p[j].y-p[k].y,p[j].z-p[k].z);
    return (v1.y*v2.z-v1.z*v2.y)+(v1.z*v2.x-v1.x*v2.z)+(v1.x*v2.y-v1.y*v2.x);
}
bool check(int i,int j,int k){
    node v1(p[k].x-p[i].x,p[k].y-p[i].y,p[k].z-p[i].z),v2(p[k].x-p[j].x,p[k].y-p[j].y,p[k].z-p[j].z);
    //向量每项必须符号相反(有一个为0,另一个也必须是0),否则两向量不相反
    if((v1.x==0&&v2.x!=0)||(v1.x!=0&&v2.x==0)) return 0;
    if((v1.y==0&&v2.y!=0)||(v1.y!=0&&v2.y==0)) return 0;
    if((v1.z==0&&v2.z!=0)||(v1.z!=0&&v2.z==0)) return 0;
    if(v1.x*v2.x>0||v1.y*v2.y>0||v1.z*v2.z>0) return 0;
    //如果A=α*B(α<0),那么A与B共线且方向相反
    if(v1.x==0&&v1.y==0&&v1.z==0) return 0;
    if(v1.x!=0&&v1.y!=0&&v1.x*v2.y!=v1.y*v2.x) return 0;
    if(v1.x!=0&&v1.z!=0&&v1.x*v2.z!=v1.z*v2.x) return 0;
    if(v1.y!=0&&v1.z!=0&&v1.y*v2.z!=v1.z*v2.y) return 0;
    return 1;
}
int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d%d",&p[0].x,&p[0].y,&p[0].z),p[0].x||p[0].y||p[0].z){
        for(int i=1;i<4;i++) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
        if(p[0]==p[1]&&p[1]==p[2]) {  //3个向量相等
            printf("%s\n",p[3]==p[0]?"YES":"NO");
            continue;
        }
        int area=abs(Cross(0,1,2));
        if(area==0){   //3条向量共面
            if(p[0]==p[1]||p[0]==p[2]||p[1]==p[2]) {
                bool flag;
                if(p[0]==p[1]) flag=check(0,2,3);
                else if(p[0]==p[2]) flag=check(0,1,3);
                else flag=check(1,2,3);
                printf("%s\n",flag?"YES":"NO");
            }
            else printf("%s\n",(check(0,1,3)||check(0,2,3)||check(1,2,3))?"YES":"NO");
        }
        else{
            //第四个点必须在三角形内
            //每个向量的可能性必须大于0,3个小三角形面积必须大于0且等于总面积
            int area1=abs(Cross(0,1,3));
            int area2=abs(Cross(0,2,3));
            int area3=abs(Cross(1,2,3));
            if(area1>0&&area2>0&&area3>0&&area==area1+area2+area3) printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值