BZOJ1574: [Usaco2009 Jan]地震损坏Damage
有n个点m条边的无向图,s个信息表示点Ai没被损坏,且到点1的路径无法只经过“未损坏的点”,求到点1路径必经“损坏的点”的点的个数的最小值。
初看毫无头绪,画个图模拟下,1--2(--5--6)--3--4,点4和6发出信息,那么有两种方式安排“损坏的点”:点2,或者点5和点3,显然后者答案更小
也就是说,一个点如果发出信息,那么他到1所有的路径中的第一个点置“损坏”,可以使答案最小。
ps:一个点到1必经损坏的点,2种情况:要么它自己损坏,要么与他连边的所有点到点1都必经损坏的点。
因此就把发出信息的每个点和与它连边的点都标记,最后bfs一次找答案的补集拿总数减掉即可。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m,s; 10 #define maxn 30011 11 #define maxm 200011 12 struct Edge{int to,next;}; 13 struct Graph 14 { 15 Edge edge[maxm];int le; 16 struct Node 17 { 18 int first;bool vis; 19 Node() {first=vis=0;} 20 }a[maxn]; 21 Graph() {le=2;} 22 void add_edge(int x,int y) 23 { 24 edge[le].to=y; 25 edge[le].next=a[x].first; 26 a[x].first=le++; 27 } 28 void insert(int x,int y) 29 { 30 add_edge(x,y); 31 add_edge(y,x); 32 } 33 void mark(int x) 34 { 35 a[x].vis=1; 36 for (int i=a[x].first;i;i=edge[i].next) 37 a[edge[i].to].vis=1; 38 } 39 int que[maxn],head,tail; 40 int bfs() 41 { 42 que[head=(tail=1)-1]=1; 43 a[1].vis=1; 44 int ans=1; 45 while (head!=tail) 46 { 47 const int now=que[head++]; 48 for (int i=a[now].first;i;i=edge[i].next) 49 if (!a[edge[i].to].vis) 50 { 51 que[tail++]=edge[i].to; 52 ans++; 53 a[edge[i].to].vis=1; 54 } 55 } 56 return ans; 57 } 58 }G; 59 int x,y; 60 int main() 61 { 62 scanf("%d%d%d",&n,&m,&s); 63 for (int i=1;i<=m;i++) 64 { 65 scanf("%d%d",&x,&y); 66 G.insert(x,y); 67 } 68 for (int i=1;i<=s;i++) 69 { 70 scanf("%d",&x); 71 G.mark(x); 72 } 73 printf("%d\n",n-G.bfs()); 74 return 0; 75 }