题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4496
题意:
给你个图,他不断删边,然后问你联通块的个数
题解:
我们可以逆向认为所有的点全是独立的,因为正向的时候去掉其中某条边的,独立的点不一定会增多(去掉这条边后还有其他边间接的相连),所以当我们逆向思考的时候,只会在增加某一条边时减少独立的点(也就是联通的点增多),这样只会在他之后才会有可能有某条边的操作是“无效”的(联通的点不变);
逆向思维好神奇撒
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 ////////////////////////////////////////////////////////////////////////// 16 const int maxn = 1e5+10; 17 18 int fa[maxn],a[maxn],b[maxn],ans[maxn]; 19 20 int find(int x){ 21 return fa[x]==x ? x : fa[x]=find(fa[x]); 22 } 23 24 bool Union(int u,int v){ 25 int t1 = find(u), t2 = find(v); 26 if(t1 == t2) return true; 27 fa[t1] = t2; 28 return false; 29 } 30 31 int main(){ 32 int n,m,tot; 33 while(scanf("%d%d",&n,&m)!=EOF){ 34 for(int i=0; i<=n; i++) 35 fa[i] = i; 36 for(int i=1; i<=m; i++) 37 a[i]=read(), b[i]=read(); 38 tot = n; 39 for(int i=m; i>=1; i--){ 40 ans[i] = tot; 41 if(Union(a[i],b[i])==0) 42 tot--; 43 } 44 for(int i=1; i<=m; i++) 45 printf("%d ",ans[i]); 46 } 47 48 return 0; 49 }