UVa 802 - Lead or Gold

11 篇文章 0 订阅
1 篇文章 0 订阅

Fuxey 最近在研究计算几何中级部分 , 很多题目网上都没有题解……..
所以决定写一些冷门的题目 , 大家有问题也欢迎咨询:-)

此题我的做法本身与计算几何无关 , 但是很受其启发。
BTW: 以后我的博客也都会先给出提示 , 然后给出代码 , 最后来详细解释。 这样大家看完提示就有自己的空间想象做法了

提示:

  1. 首先看每一个比例式的项数 , 3项 , 那么很容易想到一个更一般的问题 , 如果有N项该怎么处理呢?
  2. 如果想N项的处理方法会让这个问题更难下手 , 但是给我们一个启发 , 既然可以一般化 , 是否可以特殊化呢? 对了先从低维度的情形想起
  3. 一维显然都是可以的除非只有0项 , 二维怎么处理呢。 先看一个特殊情形 , 两个比例式按1:1相加会是这个样子:1:4 + 2:3 = 3:7
  4. 有没有什么联想呢? 当时我想到这里就豁然开朗了……
#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;
}

详细说明:

  1. 呈上 , 刚刚那个比例式的相加有没有像向量的加法呢? 还记得高中课本吗 , 两个不相等的向量可以表示任意一个向量。(不就是解方程吗)
  2. 三个向量的情形也可以以此类推 , 其实就是解方程 , 但是要保证得到的解是正数 , 所以要加以验证
  3. 如果单单就是枚举三个然后判断一次会WA , 比如考虑下面这个情形:
    7x+0.5z=6.53.7y+2.9z=12

看起来好像没什么问题但是把X替换Z代到第二个式子中就会发现: 3.7y+42x=27
这不满足要求 , 怎么处理呢? 对了 , 把 x y z <script type="math/tex" id="MathJax-Element-85">z</script>交换位置分别消元即可

Update: 后来我才知道这个题的正解是floyd求闭包 , 可以参考BZOJ第一页的某题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值