题目描述
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");
}

京公网安备 11010502036488号