1. 程式人生 > >2015年廣東省中學生資訊學奧林匹克競賽汕頭市隊選拔賽-高中組 中國石油 還錢問題

2015年廣東省中學生資訊學奧林匹克競賽汕頭市隊選拔賽-高中組 中國石油 還錢問題

5700: 還錢問題

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 49  解決: 12
[提交][狀態][討論版]

題目描述

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。

輸出

只有一行,即最少的還錢行為次數。

樣例輸入

30 1 00 0 11 0 0

樣例輸出

0

提示

第一個樣例解釋:1借給2 一塊錢,2借給3一塊錢,3借給1一塊錢,這樣實際上每個人就已經不欠其他人錢了,所以不用還錢

來源

就是還錢嗎,最小還錢行為,能內部交換就交換了,不能的再想辦法唄。感覺類似於那種模擬,但是要以一種最優的思想去考慮,可以近似於貪心的想法。然而比賽的時候沒搞出來。

int a[20][20];
int b[20][20];
int c[20]; 
int t,n;
void find()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(c[i]==(-c[j]) && c[i]!=0)
            {
                c[i]=0;
                c[j]=0;
                t++;
            }
        }
    }
}
void m()
{
    int maxx=1;
    int minn=1;
    for(int i=1;i<=n;i++)
        if(c[i]>c[maxx])
            maxx=i;
    for(int i=1;i<=n;i++)
        if(c[i]<c[minn])
            minn=i;
    if(maxx==minn)
        return ;
    c[maxx]=c[maxx]+c[minn];
    c[minn]=0;
    t++;
}
int main()
{
    t=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    }
    for(int i=1;i<=n;i++)//求出來第i個人借出去多少錢
    {
        for(int j=1;j<=n;j++)
        {
            b[i][1]=b[i][1]+a[i][j];
        }
    }
    for(int j=1;j<=n;j++)//求出來第j個人借了多少錢
    {
        for(int i=1;i<=n;i++)
        {
            b[j][2]=b[j][2]+a[i][j];
        }
    }
    for(int i=1;i<=n;i++)
    {
        c[i]=b[i][1]-b[i][2];
    }
    for(int i=1;i<=n;i++)
    {
        find();
        m();
    }
    printf("%d\n",t);
    return 0;   
}