2015年廣東省中學生資訊學奧林匹克競賽汕頭市隊選拔賽-高中組 中國石油 還錢問題
阿新 • • 發佈:2019-01-22
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; }