【2019牛客暑期多校训练营(第二场) - D】Kth Minimum Clique(bfs,tricks)
題干:
鏈接:https://ac.nowcoder.com/acm/contest/882/D
來源:牛客網
?
Given a vertex-weighted graph with N vertices, find out the K-th minimum weighted clique.
A subset of vertices of an undirected graph is called clique if and only if every two distinct vertices in the subset are adjacent. The weight of a clique is the summation of the weight of vertices in it.
輸入描述:
The first line of input contains two space-separated integers N, K. The second line of input contains N space-separated integers wiw_iwi? representing the weight of each vertex. Following N lines each contains N characters eije_{ij}eij?. There's an edge between vertex i and vertex j if and only if eij="1"e_{ij} =\texttt{"1"}eij?="1".1≤N≤1001 \leq N \leq 1001≤N≤100 1≤K≤1061 \leq K \leq 10^61≤K≤106 0≤wi≤1090 \leq w_i \leq 10^90≤wi?≤109 eij∈"01"e_{ij} \in \texttt{"01"}eij?∈"01" eii="0"e_{ii} = \texttt{"0"}eii?="0" eij=ejie_{ij} = e_{ji}eij?=eji?輸出描述:
Output one line containing an integer representing the answer. If there's less than K cliques, output "-1"\texttt{"-1"}"-1".示例1
輸入
復制
2 3 1 2 01 10輸出
復制
2說明
An empty set is considered as a clique.題目大意:
定義一個團的權值就是團中點的權值和。給定一個n個點的圖(n<=100),求第K大的團。(K<=1e6)
解題報告:
其實是考慮到:因為是個團,而不是連通圖,所以會有一些性質。
其實看到這題,第一反應肯定是2^100枚舉,這樣肯定是沒錯的。考慮時間耗費在哪里了呢?因為有一些根本不是團的情況也被你搜索到了。所以考慮優化:直接在團的基礎上進行搜索枚舉,但是還有個問題,那就是他萬一是個完全圖,那還是2^100次方呀。
但是還好,這題告訴你了K<=1e6,所以肯定要在這上面做點文章。還是按照剛剛的想法的話肯定是搜索所有的團,然后排個序輸出第k個值,但是如果是完全圖的話,那團的大小就有2^100個,肯定不能搜索完所有的團,那么考慮,K既然是已知的了,可不可以只搜索到前K大?所以思路就是優先隊列的bfs,直接搜到K個就停止,這樣總復雜度就是nlogn了。
注意這題有個小坑,那就是不bfs的過程中,加入新節點的時候需要去重,不然肯定能WA啊、、為了處理這個事情有好多種辦法,可以直接HASH,也可以用代碼中的方法:記錄最后個有效節點是哪個節點,下次直接在這個往后面搜索。原理是因為你bfs每一層的時候都保證了只加入一個節點,所以你在此時前面的點都判斷過了,所以不需要再加入了。但是你如果不這樣判斷一波的話,肯定就會有重復的團被算了多次。
貼一個題解:
我們發現我們很難直接高效的算出一張圖的第k小團的權值。因此,我們考慮將這個問題轉化一下。我們發現,因為權值都是正數,因此如果在一個已知的團上能夠再增加一個新結點形成團,那么新的團的權值必定增加。因此,我們如果從空集不斷往上去增加新的結點構造成團,那么在這個過程中,權值一定是不斷增加的。因此我們只需要從小到大拓展團,并將當前的團的權值丟進一個優先隊列里進行維護,最后不斷獲取到第k小的權值即可。至此,我們需要考慮如何能夠高效的在一個團上增加新的結點。我們還可以考慮每次只加當前點后面的點,避免重復。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<bitset> #include<set> #include<string> #include<cmath> #include<cstring> #define FF first #define SS second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 100 + 5; struct Node {bitset<105> bs;ll w;int last;Node(){}Node(bitset<105> bs,ll w,int last):bs(bs),w(w),last(last){}bool operator<(const Node b)const {return w > b.w;} }; bitset<105> a[MAX]; int n,k,val[MAX]; ll bfs() {priority_queue<Node> pq;bitset<105> bb(0);k--;pq.push(Node(bb,0,0));while(pq.size()) {Node cur = pq.top();pq.pop();if(k == 0) return cur.w;k--;for(int i = cur.last+1; i<=n; i++) {if(cur.bs[i])continue;//==1????if((cur.bs & a[i]) == cur.bs) {cur.bs[i] = 1;pq.push(Node(cur.bs,cur.w + val[i],i));cur.bs[i] = 0;}} }return -1; } int main() {cin>>n>>k;for(int i = 1; i<=n; i++) cin>>val[i];for(int x,i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) {scanf("%1d",&x);if(x == 1) a[i][j]=1;}}ll ans = bfs();printf("%lld\n",ans);return 0 ; }錯誤代碼:
錯誤原因就是因為剛開始忘記去重了。
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<bitset> #include<set> #include<string> #include<cmath> #include<cstring> #define FF first #define SS second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 100 + 5; struct Node {bitset<105> bs;ll w;Node(){}Node(bitset<105> bs,ll w):bs(bs),w(w){}bool operator<(const Node b)const {return w > b.w;} }; bitset<105> a[MAX]; int n,k,val[MAX]; ll bfs() {priority_queue<Node> pq;bitset<105> bb(0);k--;pq.push(Node(bb,0));while(pq.size()) {Node cur = pq.top();pq.pop();if(k == 0) return cur.w;k--;for(int i = 1; i<=n; i++) {if(cur.bs[i]) continue;//==1????if((cur.bs & a[i]) == cur.bs) {cur.bs[i] = 1;pq.push(Node(cur.bs,cur.w + val[i]));cur.bs[i] = 0;}}}return -1; } int main() {cin>>n>>k;for(int i = 1; i<=n; i++) cin>>val[i];for(int x,i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) {scanf("%1d",&x);if(x == 1) a[i][j]=1;}}ll ans = bfs();printf("%lld\n",ans);return 0 ; }?
總結
以上是生活随笔為你收集整理的【2019牛客暑期多校训练营(第二场) - D】Kth Minimum Clique(bfs,tricks)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 启动Autodesk Desktop L
- 下一篇: 联想一体机如何重装系统?联想一体机系统重