hiho一下 第五十六周 #1195 : 高斯消元·一 【高斯消元--】

#1195 : 高斯消元·一

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

小Ho:喂不得了啦,那边便利店的薯片半价了!

小Hi:啥?!

小Ho:那边的便利店在打折促销啊。

小Hi:走走走,赶紧去看看=v=

于是小Hi和小Ho来到了便利店。

老板为了促销,推出了组合包的形式,将不同数量的各类商品打包成一个组合,顾客可以选择组合进行购买。比如2袋薯片,1听可乐的组合只要5元,而1袋薯片,2听可乐的组合只要4元。

通过询问老板,小Hi和小Ho知道:一共有N种不同的商品和M种不同的商品组合;每一个组合的价格等于组合内商品售价之和,一个组合内同一件商品不会超过10件。

小Hi:这样算下来的话,一听可乐就是1元,而一包薯片是2元。小Ho,如果你知道所有的组合情况,你能分别算出每一件商品单独的价格么?

小Ho:当然可以了,这样的小问题怎么能难到我呢?

   

提示:高斯消元

 
输入

第1行:2个正整数,N,M。表示商品的数量N,组合的数量M。1≤N≤500, N≤M≤2*N

第2..M+1行:N+1个非负整数,第i+1行第j列表示在第i个组合中,商品j的数量a[i][j]。第i+1行第N+1个数表示该组合的售价c[i]。0≤a[i][j]≤10, 0≤c[i]≤10^9

输出

若没有办法计算出每个商品单独的价格,输出"No solutions"

若可能存在多个不同的结果,输出"Many solutions"

若存在唯一可能的结果,输出N行,每行一个非负整数,第i行表示第i个商品单独的售价。数据保证如果存在唯一解,那么解一定恰好是非负整数解。

样例输入
2 2
2 1 5
1 2 4
样例输出
2
1


呜呜,我开始一直用的longlong呀-----WA了一页了-----


用longlong相消时,最小公倍数可能超long long ----


附下自认为完整的long long版---

#include<cstdio>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
#define LL long long
LL shu[1200][600],ans[1200];
LL gcd(LL a,LL b)
{
    if (a<b)
    {
        LL c=a;
        a=b;
        b=c;
    }
    if (b==0) return a;
    return gcd(b,a%b);
}
LL gg(LL a,LL b)
{
    int aa,bb;
    aa=bb=0;
    if (a<0) a=-a,aa=1;
    if (b<0) b=-b,bb=1;
    LL yu=gcd(a,b);
    a/=yu;
    if  (aa) a=-a;
    if  (bb) a=-a;
    return a;
}
int main()
{
    int n,m,i,j;//printf("%lld   %lld   %lld   %lld\n",gcd(0,2),gcd(2,0),gcd(1,2),gcd(0,0));
    LL yu;bool fafe[2];
    fafe[1]=fafe[0]=false;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;i++)
        for (j=1;j<=n+1;j++)
            scanf("%lld",&shu[i][j]);
    //输入完成===
    stack <int > que;
    for (i=1;i<=m;i++)//化简---消零---
    {
        yu=abs(shu[i][1]);
        for (j=2;j<=n+1;j++)
            yu=gcd(yu,abs(shu[i][j]));
        if (yu)
        {
            if (yu!=1)
            for (j=1;j<=n+1;j++)
                shu[i][j]/=yu;
        }
        else
        que.push(i);
    }
    while (!que.empty())
    {
        int k=que.top();
        que.pop();
        for (int pp=1;pp<=n+1;pp++)
            shu[k][pp]=shu[m][pp];
        m--;
    }
    int lie=1,op,c;
    for (i=1;i<=n+1&&lie<m;i++)
    {
        op=0;//找一个近0首项
        for (j=lie;j<=m;j++)
            if (shu[j][i])
            {
                if (!op)
                    op=j;
                else if (abs(shu[j][i])<abs(shu[op][i]))
                    op=j;
            }
        if (!op)//这一列全0--
            continue;
        if (op!=lie)//交换lie行和op行
        {
            for (int k=1;k<=n+1;k++)
            {
                c=shu[op][k];
                shu[op][k]=shu[lie][k];
                shu[lie][k]=c;
            }
        }
        for (int k=lie+1;k<=m;k++)//用lie行来消下面的行
        {
            if (!shu[k][i]) continue;
            yu=gg(shu[lie][i],shu[k][i]);
            LL kop=shu[k][i]*yu/shu[lie][i];//通分
            for (int kl=i;kl<=n+1;kl++)//消--
                shu[k][kl]=shu[k][kl]*yu-kop*shu[lie][kl];
            yu=abs(shu[k][i]);//化简
            for (int kl=i+1;kl<=n+1;kl++)
                yu=gcd(yu,abs(shu[k][kl]));
            if (yu)
            {
                if (yu!=1)
                {
                    for (int kl=i;kl<=n+1;kl++)
                    shu[k][kl]/=yu;
                }
            }
            else
                que.push(k);
        }
        lie++;
        while (!que.empty())//消空行
        {
            int k=que.top();
            que.pop();
            for (int pp=1;pp<=n+1;pp++)
                shu[k][pp]=shu[m][pp];
            m--;
        }
    }
//    for (i=1;i<=m;i++)
//   {
//        for (j=1;j<=n+1;j++)
//           printf("%lld ",shu[i][j]);
//       printf("\n");
//    }
    fafe[1]=true;//0=C--------无解的情况
    for (i=1;i<=n;i++)
        if (shu[m][i])
            fafe[1]=false;
    if (fafe[1])
        printf("No solutions\n");
    else if (m!=n)
        printf("Many solutions\n");
    else
    {
        for (j=n;j>0;j--)
        {
            ans[j]=shu[j][n+1];
            for (int k=n;k>j;k--)
                ans[j]-=ans[k]*shu[j][k];
            ans[j]/=shu[j][j];
        }
        for (i=1;i<=n;i++)
            printf("%lld\n",ans[i]);
    }
    return 0;
}



用double的需要自设一个近0值---10^-n 次方---


代码:

#include<cstdio>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
#define LL long long
double shu[1200][600],ans[1200];
int cinn[1200];
int main()
{
    int n,m,i,j;
    LL yu;bool fafe[2];
    while (~scanf("%d%d",&n,&m))
    {
        fafe[1]=fafe[0]=false;
        double ling=0.000001;
        for (i=1;i<=m;i++)
            for (j=1;j<=n+1;j++)
                scanf("%lf",&shu[i][j]);
        //输入完成===
        stack <int > que;
        bool yy,xx;
        double  xie;
        int lie=1,op;//lie表示我们要用第lie行去消下面的行
        double c;
        for (i=1;i<=n;i++)
        {
            op=0;//找一个近0首项
            for (j=lie;j<=m;j++)
                if (fabs(shu[j][i])>ling)
                {
                    op=j;
                    break;
                }
            if (!op)//这一列全0或行数不够--不是无解就是多解-.-然后i后移---用lie行消i+1列
            {
                fafe[0]=true;
                continue;
            }
            if (op!=lie)//交换lie行和op行
            {
                for (int k=1;k<=n+1;k++)
                {
                    c=shu[op][k];
                    shu[op][k]=shu[lie][k];
                    shu[lie][k]=c;
                }
            }
            for (int k=lie+1;k<=m;k++)//用lie行来消下面的行
            {
                xie=shu[k][i]/shu[lie][i];//这里精良不要用b=b*k-a;---会使后项越变越大-.-
                for (int mm=i;mm<=n+1;mm++)
                    shu[k][mm]-=shu[lie][mm]*xie;
            }
            for (int k=m;k>lie;k--)//消0行-.-这一步也可以无视
            {
                xx=true;
                for (j=1;j<=n+1;j++)
                if (fabs(shu[k][j])>ling)
                {
                    xx=false;
                    break;
                }
                if (xx)
                {
                    if (k!=m)
                    for (j=1;j<=n+1;j++)
                        shu[k][j]=shu[m][j];
                    m--;
                }
            }
            lie++;
        }
        for (i=1;i<=m;i++)//无解的情况--
        {
            if (fabs(shu[i][n+1])>ling)
                fafe[1]=true;
            for (j=1;j<=n;j++)
                if (fabs(shu[i][j])>ling)
            {
                fafe[1]=false;break;
            }
            if (fafe[1]) break;
        }
        if (fafe[1])
        {
            printf("No solutions\n");
            continue;
        }
        else if (fafe[0])
            printf("Many solutions\n");
        else
        {
            for (j=n;j>0;j--)
            {
                ans[j]=shu[j][n+1];
                for (int k=n;k>j;k--)
                    ans[j]-=ans[k]*shu[j][k];
                ans[j]/=shu[j][j];
            }
            for (i=1;i<=n;i++)
                cinn[i]=(int)(ans[i]+0.5);
            for (int i=1;i<=n;i++)
                printf("%d\n",cinn[i]);
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值