求能覆盖到所有点的最少集合情况(超时题,须优化)

来源:互联网 发布:淘宝象印官方旗舰店 编辑:程序博客网 时间:2024/04/26 14:27
4       //t组样例3 5     //3个集合,5个点2 2 1   //2大小,覆盖点2和点11 4     //1大小,覆盖点42 3 5   //2大小,覆盖点3和点5
3 3     //3个集合,3个点3 1 2 3 //3大小,覆盖点1和点2和点33 2 3 1 //3大小,覆盖点2和点3和点13 3 1 2 //3大小,覆盖点3和点1和点23 32 1 22 2 32 3 1
3 32 2 31 12 1 3

Sample Output

31 2 3
11
21 2
21 2
一个很容易想到的做法:
#include<iostream>#include<algorithm>#include<string>#include<map>#include<cmath>#include<string.h>#include<stdlib.h>#include<cstdio>#define ll long longusing namespace std;int main(){int t;cin>>t;while(t--){int n,m,a,b;cin>>n>>m;int minn=100000000,p;for(int i=0;i<n;++i){cin>>a;for(int j=0;j<a;++j){cin>>b;y[i].push_back(b);}}for(int i=1;i<(1<<n);++i){map<int,int> r;for(int j=0;j<n;++j){if(i&(1<<j)){for(int k=0;k<y[j].size();++k){r[y[j][k]]=1;}}}if(r.size()==m){......}}......}return 0;}
但是复杂度会爆。所以用下面的做法:
#include<iostream>#include<algorithm>#include<string>#include<map>#include<cmath>#include<string.h>#include<stdlib.h>#include<cstdio>#define ll long longusing namespace std;int x[65];int main(){int t;cin>>t;while(t--){memset(x,0,sizeof(x));int n,m,a,b;cin>>n>>m;int minn=100000000,p;for(int i=0;i<n;++i){cin>>a;for(int j=0;j<a;++j){cin>>b;x[b]|=(1<<i);}}for(int i=1;i<(1<<n);++i){int w=0,h=i,s=0;while(h>0){w+=h%2;h/=2;}for(int j=1;j<=m;++j){if(x[j]&i)  //如果i里面包含至少一个有j的位s++; }if(s==m){if(w<minn){minn=w;p=i;}}}cout<<minn<<endl;int s=1,w=1;while(p>0){if(p%2==1){if(s<minn)cout<<w<<" ";elsecout<<w<<endl;s++;}p/=2;w++;}}return 0;}


0 0