2018山东冬令营:还钱问题,UPC(5700) 还钱问题

5700: 还钱问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 54  解决: 14
[提交][状态][讨论版]

题目描述

STOI团队里的兄弟们脑子里装满算法,出门经常忘了带钱,于是经常有甲向乙借钱买大饼,乙向丙借钱买饮料这种事发生。
换成OI语言描述就是:这团队有N个人,每个人都跟别人借了一些钱,也借了一些钱给别人,同时满足他们借出去或者借来的钱都在这N个人当中,即总量不变。
现在定义一个还钱行为:A B C 表示A还钱给B,钱的数额为C。
问题:最少需要多少个还钱行为才能使得这N个人的债务结清(即每个人都不欠别人钱,也没有人欠他的钱)

输入

第一行是N,表示有N个人(1 <= N <= 14)
下面是一个N行N列的矩阵A, A[i, j] = k表示i借给j钱,数额为k。

输出

只有一行,即最少的还钱行为次数。

样例输入

3
0 1 0
0 0 1
1 0 0

样例输出

0

提示

第一个样例解释:1借给2 一块钱,2借给3一块钱,3借给1一块钱,这样实际上每个人就已经不欠其他人钱了,所以不用还钱


【题意】

中文题意,很好理解

【思路】

每个人都有支出和收入,  那么  一个人的 收入与支出的 差值时可以计算出来的。

把差值计算出来,  然后贪心查找, 先去找等价的,  这样就 不用抵消,  其次 去找最大与最小的贪心;

【代码实现】

#include <iostream>
#include <bits/stdc++.h>
 
using namespace std;
 
int maps[500][500];
 
const int MAXN=500;
vector<int> V;
int a[MAXN],b[MAXN],c[MAXN];
int cot=0;
int n;
void finds(int x)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(c[i]==(-c[j])&&c[i]!=0)
                c[i]=c[j]=0,cot++;
        }
    }
}
void ojbk()
{
    int  m1=1,m2=1;
    for(int i=1;i<=n;i++)
    {
        if(c[i]>c[m1])
            m1=i;
        if(c[i]<c[m2])
            m2=i;
    }
    if(m1==m2)
        return ;
    c[m2]+=c[m1];
    c[m1]=0;cot++;
}
int main()
{
 
    memset(maps,0,sizeof(maps));
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>maps[i][j];
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            a[i]+=maps[i][j];
            b[j]+=maps[i][j];
        }
    }
    for(int i=1;i<=n;i++)
    {
        c[i]=a[i]-b[i];
        //cout<<c[i]<<endl;
    }
    for(int i=1;i<=n;i++)
    {
        finds(i);
        ojbk();
    }
    cout<<cot<<endl;
    return 0;
}

123

posted @ 2018-03-04 10:01  Sizaif  阅读(220)  评论(0编辑  收藏  举报