1848: 3-sided dice
Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 42 Solved: 5Description
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
题解:把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;
}