一般图的最小点覆盖问题是是一个npc问题,目前哈没有比较好的多项式的算法。但是这题有一点特殊的地方,每条边必定包含前面30个点的的一个,所以这题可以枚举钱30个点的选和不选的状态,后面的点对应的状态就唯一了。 所以这题就是 dfs+可行性减枝和答案最优减枝。
#include<stdio.h> #include<string.h> #include<iostream> #include<string> #include<queue> #include<cmath> #include<map> #include<algorithm> #include<vector> #include<bitset> using namespace std; const int mmax = 510; const int inf =0x3fffffff; int n,m; struct node { int en; int next; }E[mmax*mmax]; int p[mmax]; int num; void add(int st,int en) { E[num].en=en; E[num].next=p[st]; p[st]=num++; } void init() { memset(p,-1,sizeof p); num=0; } int fg[510]; int Cnt[510]; void build(int x) { int tmp=0; Cnt[x]=0; for(int i=p[x];i+1;i=E[i].next) { int v=E[i].en; if(v<30) tmp|=(1<<v); if(v>=30) Cnt[x]++; } fg[x]=tmp; } int solve(int falg) { int cnt=0; for(int i=30;i<n;i++) { if((falg&fg[i])!=fg[i]) cnt++; } return cnt; } int ans; bool ok(int u,int falg) { for(int i=u;i<30;i++) falg|=(1<<i); for(int i=0;i<30;i++) { if( !(falg&(1<<i)) &&(falg&fg[i])!=fg[i]) return 0; } return 1; } void dfs(int u,int falg,int cnt) { if(!ok(u,falg)) return ; int tmp=falg; for(int i=u;i<30;i++) tmp|=(1<<i); if(cnt+solve(tmp)>=ans) return ; if(u>=30) { ans=min(ans,cnt+solve(falg)); return ; } if((falg&fg[u])==fg[u] && !Cnt[u]) { dfs(u+1,falg,cnt); return ; } dfs(u+1,falg,cnt); dfs(u+1,falg|(1<<u),cnt+1); } int main() { while(~scanf("%d %d",&n,&m)) { init(); for(int i=0;i<m;i++) { int u,v; scanf("%d %d",&u,&v); u--,v--; add(u,v); add(v,u); } memset(fg,0,sizeof fg); for(int i=0;i<n;i++) build(i); ans=30; dfs(0,0,0); printf("%d\n",ans); } return 0; }
时间: 2024-09-29 13:16:02