[POI2013]Tower Defense Game
题目大意:
一个$n(n\le5\times10^5)$个点$m(m\le10^6)$条边的无向图,边权全为$1$,满足若一个标记点能覆盖与其距离不超过$1$的点,从中选取不超过$k$个点能将整张图覆盖。问若一个标记点能覆盖与其距离不超过$2$的点,求构造一种选取点数不超过$k$的方案将整张图覆盖。
思路:
贪心,每次选取没有覆盖的点作为标记点,并更新覆盖点的和。选取一个点后增加的覆盖范围一定完全包含原来覆盖这个点的标记点的覆盖范围,因此方案一定更优。
1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 register char ch; 5 while(!isdigit(ch=getchar())); 6 register int x=ch^'0'; 7 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 8 return x; 9 } 10 const int N=5e5+1,M=2e6+1; 11 bool b[N],vis[N]; 12 int h[N],ans[N]; 13 struct Edge { 14 int to,next; 15 }; 16 Edge e[M]; 17 inline void add_edge(const int &u,const int &v) { 18 e[++h[0]]=(Edge){v,h[u]};h[u]=h[0]; 19 e[++h[0]]=(Edge){u,h[v]};h[v]=h[0]; 20 } 21 int main() { 22 const int n=getint(),m=getint(),k=getint(); 23 for(register int i=0;i<m;i++) { 24 add_edge(getint(),getint()); 25 } 26 for(register int x=1;x<=n;x++) { 27 if(vis[x]) continue; 28 ans[++ans[0]]=x; 29 vis[x]=b[x]=true; 30 for(register int i=h[x];i;i=e[i].next) { 31 const int &y=e[i].to; 32 if(b[y]) continue; 33 vis[y]=true; 34 for(register int i=h[y];i;i=e[i].next) { 35 const int &z=e[i].to; 36 vis[z]=true; 37 } 38 } 39 } 40 printf("%d\n",ans[0]); 41 for(register int i=1;i<=ans[0];i++) { 42 printf("%d%c",ans[i]," \n"[i==ans[0]]); 43 } 44 return 0; 45 }