题目描述
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.
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 wiwi representing the weight of each vertex. Following N lines each contains N characters eijeij. There's an edge between vertex i and vertex j if and only if eij="1"eij="1". 1≤N≤1001≤N≤100 1≤K≤1061≤K≤106 0≤wi≤1090≤wi≤109 eij∈"01"eij∈"01" eii="0"eii="0" eij=ejieij=eji
输出描述:
Output one line containing an integer representing the answer. If there's less than K cliques, output "-1""-1".
示例1
说明
An empty set is considered as a clique.
我们发现我们很难直接高效的算出一张图的第k小团的权值。因此,我们考虑将这个问题转化一下。我们发现,因为权值都是正数,因此如果在一个已知的团上能够再增加一个新结点形成团,那么新的团的权值必定增加。因此,我们如果从空集不断往上去增加新的结点构造成团,那么在这个过程中,权值一定是不断增加的。因此我们只需要从小到大拓展团,并将当前的团的权值丢进一个优先队列里进行维护,最后不断获取到第k小的权值即可。至此,我们需要考虑如何能够高效的在一个团上增加新的结点。
我们还可以考虑每次只加当前点后面的点,避免重复,下面贴一个不用bitset写的代码,如果超时可能是网络波动问题,再交一发就行了。
#include<bits/stdc++.h> using namespace std; #define ll long long #define INF 0x3fffffff #define maxn 100005 #define mod 1000000000 int n,m,k,t; ll u[105]; struct ac{ ll wight; int z; vector<int>dis; bool operator<(const ac & x)const{return wight>x.wight;} }a[105],f; bool ma[105][105]; priority_queue<ac>q; int main(){ scanf("%d%d",&n,&k); k--;//最小为一个点都没有的团,要删去 for(int i=1;i<=n;i++)scanf("%d",&u[i]); getchar(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ char c=getchar(); if(c=='1') ma[i][j]=1; } getchar(); } if(k==0){ puts("0"); return 0; } for(int i=1;i<=n;i++){//先把每个点都放入优先队列 a[i].wight=u[i]; a[i].z=0; a[i].dis.push_back(i); q.push(a[i]); } while(!q.empty()){ f=q.top();//取出当前最小的团 k--; q.pop(); if(k==0){ printf("%lld\n",f.wight); return 0; } int now=f.dis[f.z]+1;//取当前点后面的点,去重 for(int i=now;i<=n;i++){ bool flag=1; for(int j=0;j<=f.z;j++){//如果新的点与之前所有点相连,加入这个团 if(ma[f.dis[j]][i]==0){ flag=0; break; } } if(flag){ f.wight+=u[i]; f.z++; f.dis.push_back(i); q.push(f); f.z--; f.dis.pop_back(); f.wight-=u[i]; } } } puts("-1"); }