5700: 还钱问题
时间限制: 1 Sec 内存限制: 128 MB提交: 74 解决: 22
[ 提交][ 状态][ 讨论版][命题人: admin]
题目描述
STOI团队里的兄弟们脑子里装满算法,出门经常忘了带钱,于是经常有甲向乙借钱买大饼,乙向丙借钱买饮料这种事发生。
换成OI语言描述就是:这团队有N个人,每个人都跟别人借了一些钱,也借了一些钱给别人,同时满足他们借出去或者借来的钱都在这N个人当中,即总量不变。
现在定义一个还钱行为:A B C 表示A还钱给B,钱的数额为C。
问题:最少需要多少个还钱行为才能使得这N个人的债务结清(即每个人都不欠别人钱,也没有人欠他的钱)
换成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。
下面是一个N行N列的矩阵A, A[i, j] = k表示i借给j钱,数额为k。
输出
只有一行,即最少的还钱行为次数。
样例输入
30 1 00 0 11 0 0
样例输出
0
提示
第一个样例解释:1借给2 一块钱,2借给3一块钱,3借给1一块钱,这样实际上每个人就已经不欠其他人钱了,所以不用还钱
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int n, book[15];
memset(book, 0, sizeof(book));
scanf("%d", &n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int x;
scanf("%d", &x);
book[i]-=x;
book[j]+=x;
}
int ans=0;
while(1)
{
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(book[i] && book[i]==-book[j])//如果此人(i)有债务并且有另外一人和他的债务正负不同,则两两抵消
{
ans++;
book[i]=book[j]=0;
}
sort(book+1, book+1+n);//债务排序
if(book[1]==0)//排序结束后第一个人没有债务,表示所有人的债务都已还清,退出循环
break;
book[n]+=book[1];//将最少的加到最多的上面
ans++;
book[1]=0;
}
printf("%d\n", ans);
return 0;
}
/**************************************************************
Problem: 5700
User: ldu_reserver201701
Language: C++
Result: 正确
Time:0 ms
Memory:1092 kb
****************************************************************/