题意:一些人有朋友关系,在某个人的社交网站上投放广告可以被所有该人的直接朋友看到,问最小投放多少个广告使给出的人都看到广告。(n<=20)
解法:看到n的范围可以想到用二进制数表示每个人被覆盖与否,所以可以依次为状态进行搜索,每次枚举一个人,投放广告,然后将他的朋友覆盖,用dis记录步数,记忆化搜索。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define Mod 1000000007 using namespace std; #define N 100007 int mp[22][22]; int mstep,n,S; int tag; int dis[1103300]; void dfs(int state,int step) { int i; dis[state] = step; if(state == S) { mstep = min(mstep,step); return; } for(int i=0;i<n;i++) { //if((state&(1<<i)) == 0) //不要,因为这个点可以是被覆盖的,还可以再放 //{ int tmp = state|(1<<i); for(int j=0;j<n;j++) { if(mp[i][j] && (tmp&(1<<j)) == 0) { tmp|=(1<<j); } } if(!dis[tmp] || step+1 < dis[tmp]) { dfs(tmp,step+1); } //} } } int main() { int t,i,k,j,x; scanf("%d",&t); while(t--) { scanf("%d",&n); S = (1<<n)-1; memset(mp,0,sizeof(mp)); memset(dis,0,sizeof(dis)); for(i=0;i<n;i++) { scanf("%d",&k); for(j=0;j<k;j++) { scanf("%d",&x); mp[i][x-1] = 1; mp[x-1][i] = 1; } } mstep = Mod; dfs(0,0); printf("%d ",mstep); } return 0; }