生活随笔
收集整理的這篇文章主要介紹了
#2991. kiki君的护盾 (shield)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
kiki君在鎮妖塔中爆出了攻擊力+8的護盾, 護盾是一個圓盤,圓盤上鑲嵌著N顆寶石,編號為0~N-1。第i顆寶石的能量是Ai。如果Ai>0,表示這顆寶石能量過高,需要把Ai的能量傳給其它寶石;如果Ai<0,表示這顆寶石的能量過低,需要從其它寶石處獲取-Ai的能量。保證∑Ai =0。只有當所有寶石的能量均相同時,護盾才會被激活,并且會持續一段時間的不受傷害和攻擊力提升至原來的5倍。
不過,只有M對寶石之間可以互相傳遞能量,其中第i對寶石之間無論傳遞多少能量,都要花費Ti的代價。kiki君想知道,最少需要花費多少代價才能使所有寶石的能量都相同?
輸入格式
輸入文件名為(shield.in)。
第一行兩個整數N、M。
第二行N個整數Ai。
接下來M行每行三個整數pi,qi,Ti,表示在編號為pi和qi的寶石之間傳遞能量需要花費Ti的代價。數據保證每對pi、qi最多出現一次。
輸出格式
輸出文件名為(shield.out)。
輸出一個整數表示答案。無解輸出Impossible
樣例
樣例輸入
3 3
50 -20 -30
0 1 10
1 2 20
0 2 100
樣例輸出
30
數據范圍與提示
對于50%的數據,2<=N<=8。
對于100%的數據,2<=N<=16,0<=M<=N*(N-1)/2,0<=pi,qi<N,-1000<=Ai<=1000,0<=Ti<=1000,∑Ai=0。
狀態壓縮+動態規劃+最小生成樹
注意:枚舉集合中的子集應為原始集合&(當前子集-1)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std
;
const int N
= 17, S
= (1 << 16) - 1, Max
= 1061109567;
int n
, m
, cost
[S
+ 1], f
[S
+ 1], fa
[N
], a
[N
], to
[N
][N
], sum
[S
+ 1];
bool flag
[S
+ 1];
struct node
{int x
, y
, val
;
} b
[400];
inline int lowbit(int x
) { return x
& (-x
); }
bool
cmp(node a
, node b
) { return a
.val
< b
.val
; }
inline int getfa(int x
) {if (fa
[x
] == x
)return x
;return fa
[x
] = getfa(fa
[x
]);
}
inline bool
kruscal(int x
) {int tot
= 0, ans
= 0;for (int i
= x
; i
; i
-= lowbit(i
)) {for (int j
= 0; j
< n
; j
++) {for (int k
= j
+ 1; k
< n
; k
++) {if (((i
>> j
) & 1) && ((i
>> k
) & 1)) {fa
[j
+ 1] = j
+ 1;fa
[k
+ 1] = k
+ 1;if (to
[j
+ 1][k
+ 1]) {b
[++tot
].x
= j
+ 1;b
[tot
].y
= k
+ 1;b
[tot
].val
= to
[j
+ 1][k
+ 1];}}}}}sort(b
+ 1, b
+ 1 + tot
, cmp
);int faa
;for (int i
= 1; i
<= tot
; i
++) {int x
= getfa(b
[i
].x
), y
= getfa(b
[i
].y
);if (x
== y
)continue;ans
+= b
[i
].val
;fa
[x
] = y
;faa
= y
;}bool pd
= true
;for (int i
= 0; i
< n
; i
++) {if (((x
>> i
) & 1) && getfa(i
+ 1) != faa
)pd
= false
;}if (pd
)cost
[x
] = ans
;return pd
;
}
inline int get(int x
) {int ans
= 0;for (int i
= 0; i
< n
; i
++)if (((x
>> i
) & 1))ans
+= a
[i
+ 1];return ans
;
}
int main() {cin
>> n
>> m
;memset(f
, 0x3f3f3f, sizeof(f
));memset(flag
, true
, sizeof(flag
));for (int i
= 1; i
<= n
; i
++) {cin
>> a
[i
];}for (int i
= 1; i
<= m
; i
++) {int x
, y
, z
;cin
>> x
>> y
>> z
;x
+= 1, y
+= 1;to
[x
][y
] = z
;to
[y
][x
] = z
;}for (int i
= 1; i
<= (1 << n
) - 1; i
++) {sum
[i
] = get(i
);if (sum
[i
] != 0)flag
[i
] = false
;if (!kruscal(i
))flag
[i
] = false
;if (flag
[i
])f
[i
] = cost
[i
];}for (int i
= 1; i
<= (1 << n
) - 1; i
++) {if (!flag
[i
])continue;for (int j
= (1 << n
) - 1 - i
; j
; j
= ((1 << n
) - 1 - i
) & (j
- 1)) {if (flag
[i
] && flag
[j
])f
[i
| j
] = min(f
[i
| j
], f
[i
] + cost
[j
]);}}if (f
[(1 << n
) - 1] == Max
)cout
<< "Impossible" << endl
;elsecout
<< f
[(1 << n
) - 1] << endl
;return 0;
}
總結
以上是生活随笔為你收集整理的#2991. kiki君的护盾 (shield)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。