Gym - 101666G Going Dutch

BAPC 2017

   The 2017 Benelux Algorithm Programming Contest

G Going Dutch

You and your friends have just returned from a beautiful vacation
in the mountains of the Netherlands. When on vacation,
it’s annoying to split the bill on every expense every time, so
you just kept all the receipts from the vacation, and wrote down
who paid how much for who. Now, it is time to settle the bill.
You could each take all the receipts showing that someone paid
something for you, and then pay that person back. But then
you would need a lot of transactions, and you want to keep up the lazy spirit from your trip.
In the end, it does not matter who transfers money to whom; as long as in the end, everyone’s
balance is 0.
Can you figure out the least number of transactions needed to settle the score? Assume
everyone has enough spare cash to transfer an arbitrary amount of money to another person.
Input
Input consists of
• A line containing two integers M, the number of people in the group, with 1  M  20,
and N, the number of receipts from the trip, with 0  N  1000.
• N lines, each with three integers a, b, p, where 0  a, b < M, and 1  p  1000,
signifying a receipt showing that person a paid p euros for person b.
Output
Output a single line containing a single integer, the least number of transactions necessary to
settle all bills.
Sample Input 1 Sample Output 1
4 2
0 1 1
2 3 1
2
Sample Input 2 Sample Output 2
5 5
0 1 3
1 2 3
2 3 3
3 4 3
4 0 3
0
16 Problem G: Going Dutch
Sample Input 3 Sample Output 3
5 4
0 1 1
0 2 1
0 3 1
0 4 1
4

【题目大意:】
n个人,m笔账,文最少多少次能还清
【题目分析:】
对于k个人来说,如果这k个人的集合正负钱数和为0(即这k个人相互还钱能还清),显然是最多还(k-1)次账的。(因为最差的情况是k-1个人都还给最后一个人)
所以就显然可以得到的是,如果我们将这n个人分波,分成k和(n-k)两个部分显然可以得到分别的还钱次数是(k-1)和(n-k-1),即总还钱次数为(k-1)+(n-k-1) = (n-2)。同理可得,如果将n个人分成x波,使得这x波分别都能还清,那么显然可以得到,只需要还(n-x)的。所以我们只需要统计最大的x,使得这x波人能还清,那么就可以轻松的得到答案了。
注: 题目分析转载于: 原文链接:https://blog.csdn.net/mengzhongsharen/article/details/79863359

//
// Created by DELL on 2020/2/29.
//
#include <iostream>
#include <cstdio>
#include <cstring>

const int Maxn = 21;
const int Maxm = 1 << 20;
int num[Maxn],ans[Maxm],sum[Maxm],n,m;
inline int max(int a,int b) {
	if(a > b) return a;
	else return b;
}

int main(int argc,char* argv[]) {
    scanf("%d%d",&n,&m);
    int a,b,p;
    memset(num,0,sizeof(num));
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&a,&b,&p);
        num[a] += p; num[b] -= p;
    }
    for(int i=0; i<(1<<n); i++) {
        sum[i] = 0;
        for(int j=0; j<n; j++)
            if(i & (1 << j)) sum[i] += num[j];
    }
    for(int i=0; i<(1<<n); i++) {
        for(int j=0; j<n; j++)
            if((i & (1 << j)) == 0)//  位运算的优先级好像比==还要低    主要那个括号  我崩了 
                ans[i | (1 << j)] = max(ans[i | (1 << j)],ans[i] + (sum[i | (1 << j)] == 0 ? 1 : 0));
    }
    printf("%d\n",n - ans[(1 << n) - 1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35776409/article/details/104573359