Fuxey 最近在研究计算几何中级部分 , 很多题目网上都没有题解……..
所以决定写一些冷门的题目 , 大家有问题也欢迎咨询:-)
此题我的做法本身与计算几何无关 , 但是很受其启发。
BTW: 以后我的博客也都会先给出提示 , 然后给出代码 , 最后来详细解释。 这样大家看完提示就有自己的空间想象做法了
提示:
- 首先看每一个比例式的项数 , 3项 , 那么很容易想到一个更一般的问题 , 如果有N项该怎么处理呢?
- 如果想N项的处理方法会让这个问题更难下手 , 但是给我们一个启发 , 既然可以一般化 , 是否可以特殊化呢? 对了先从低维度的情形想起
- 一维显然都是可以的除非只有0项 , 二维怎么处理呢。 先看一个特殊情形 , 两个比例式按1:1相加会是这个样子:1:4 + 2:3 = 3:7
- 有没有什么联想呢? 当时我想到这里就豁然开朗了……
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <deque>
#include <algorithm>
#include <list>
#include <queue>
using namespace std;
typedef double Matrix[4][4];
const double eps = 1e-10;
int dcmp(double a) { return fabs(a)<eps?0:(a<0?-1:1); }
const int maxn = 110;
int n;
double a[maxn];
double b[maxn];
double c[maxn];
bool gaussJohdan(Matrix a)
{
int n = 3;
for(int i=0;i<n;i++)
{
int r = i;
for(int j=i+1;j<n;j++) if(fabs(a[j][i]) > fabs(a[r][i])) r = j;
if(dcmp(a[r][i])==0) continue;
if(r!=i) for(int j=0;j<=n;j++) swap(a[r][j] , a[i][j]);
for(int j=0;j<n;j++) if(i!=j) for(int k=n;k>=i;k--) a[j][k] -= a[j][i]/a[i][i]*a[i][k];
}
for(int i=0;i<n;i++)
{
int xs = 0;
for(int j=0;j<n;j++) if(dcmp(a[i][j])) xs++;
if(xs==0) { if(dcmp(a[i][n])) return false; continue; }
if(xs==1) { if(dcmp(a[i][n]/a[i][i])==-1) return false; else continue; }
if(dcmp(a[i][n])==-1) for(int j=0;j<=n;j++) a[i][j]*=-1;
bool Pos = false;
for(int j=0;j<n;j++) if(dcmp(a[i][j])==1) { Pos = true; break; }
if(!Pos) return false;
}
return true;
}
bool solve(int n)
{
for(int i=0;i<n;i++) for(int j=i;j<n;j++) for(int k=j;k<n;k++)
{
Matrix now , hi;
now[0][0] = a[i]; now[0][1] = a[j]; now[0][2] = a[k]; now[0][3] = a[n];
now[1][0] = b[i]; now[1][1] = b[j]; now[1][2] = b[k]; now[1][3] = b[n];
now[2][0] = c[i]; now[2][1] = c[j]; now[2][2] = c[k]; now[2][3] = c[n];
bool ok = true;
int order[]={0,1,2};
do
{
for(int ii=0;ii<3;ii++)
{
int jj = order[ii];
for(int kk=0;kk<3;kk++) hi[kk][jj] = now[kk][ii];
}
for(int ii=0;ii<3;ii++) hi[ii][3] = now[ii][3];
if(!gaussJohdan(hi)) { ok = false; break; }
}while(next_permutation(order , order+3));
if(ok) return true;
}
return false;
}
int main()
{
freopen("in","r",stdin);
int n , Case=0;
while(cin>>n && n)
{
if(Case)cout<<endl;
for(int i=0;i<=n;i++) cin>>a[i]>>b[i]>>c[i];
cout<<"Mixture "<<++Case<<endl<<(solve(n)?"Possible":"Impossible")<<endl;
}
return 0;
}
详细说明:
- 呈上 , 刚刚那个比例式的相加有没有像向量的加法呢? 还记得高中课本吗 , 两个不相等的向量可以表示任意一个向量。(不就是解方程吗)
- 三个向量的情形也可以以此类推 , 其实就是解方程 , 但是要保证得到的解是正数 , 所以要加以验证
- 如果单单就是枚举三个然后判断一次会WA , 比如考虑下面这个情形:
⎧⎩⎨⎪⎪−7x+0.5z=6.53.7y+2.9z=12
看起来好像没什么问题但是把X替换Z代到第二个式子中就会发现:
3.7y+42x=−27
这不满足要求 , 怎么处理呢? 对了 , 把
x
,
Update: 后来我才知道这个题的正解是floyd求闭包 , 可以参考BZOJ第一页的某题