标签:main algo 内网 problems 必须 span 双向 最小 one
【数据范围】
对于30%的数据,保证N < =1000
对于100%的数据,保证N < =1000000
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<vector> 10 #define N 1000005 11 using namespace std; 12 int n,zz,a[N]; 13 struct ro 14 { 15 int to,next; 16 }road[N*3]; 17 void build(int x,int y) 18 { 19 zz++; 20 road[zz].to=y; 21 road[zz].next=a[x]; 22 a[x]=zz; 23 } 24 int b[N]; 25 bool fw[N],fw2[N]; 26 bool find(int x) 27 { 28 for(int i=a[x];i>0;i=road[i].next) 29 { 30 int y=road[i].to; 31 if(!fw[y]) 32 { 33 fw[y]=1; 34 if(!b[y]) 35 { 36 b[y]=x; 37 return 1; 38 } 39 } 40 } 41 for(int i=a[x];i>0;i=road[i].next) 42 { 43 int y=road[i].to; 44 if(!fw2[y]) 45 { 46 fw2[y]=1; 47 if(find(b[y])) 48 { 49 b[y]=x; 50 return 1; 51 } 52 } 53 } 54 return 0; 55 } 56 int js[N]; 57 int main() 58 { 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++) 61 { 62 int x,y; 63 scanf("%d%d",&x,&y); 64 js[x]++,js[y]++; 65 build(x,i); 66 build(y,i); 67 } 68 int ans=0; 69 for(int i=1;i<=min(n,10000);i++) 70 { 71 if(!js[i])break; 72 memset(fw,0,sizeof(fw)); 73 memset(fw2,0,sizeof(fw2)); 74 if(find(i))ans++; 75 else break; 76 } 77 printf("%d\n",ans); 78 return 0; 79 }
下面我来说一下正解:并查集。
当时在思考时并不是没想到过并查集,但如何去保证递增这个条件没想出来,然后就放弃这个思路了。合并那些并查集十分好说,毕竟怎么搞也只能从武器的两个权值做文章那如何保证递增呢?
首先我们明确一个性质当当前连通块是一个树时,如果我们再去加一个边这个图中一定有一个环,而如果所有边都是双向边,我们可以满足每一个点都可以和一个与之相连的边配对且所有边不重复。
那么当我们在并查集合并的时候,我们可以分类讨论,如果说两个节点所属同一个并查集,那么这个并查集里所有的点都可以被满足,如果两个点属于不同并查集,那么我们根据递增的要求,首先看编号小的并查集是否已经被满足,若被满足我们就去满足大的,否则就去满足小的就好了。在合并时我们应当把大的作为小的的fa,否则我们每次满足的标记都只能打给最小的,无法真正更新答案。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<vector> 10 #define N 1000005 11 using namespace std; 12 int n,fa[N]; 13 bool vi[N]; 14 int find(int x) 15 { 16 if(fa[x]==x) return x; 17 return fa[x]=find(fa[x]); 18 } 19 void hb(int x,int y) 20 { 21 int a=find(x),b=find(y); 22 if(a>b)swap(a,b); 23 if(a==b) vi[a]=1; 24 else 25 { 26 if(!vi[a]) vi[a]=1; 27 else vi[b]=1; 28 fa[a]=b; 29 } 30 } 31 int main() 32 { 33 scanf("%d",&n); 34 for(int i=1;i<=10000;i++) 35 fa[i]=i; 36 for(int i=1;i<=n;i++) 37 { 38 int x,y; 39 scanf("%d%d",&x,&y); 40 hb(x,y); 41 } 42 for(int i=1;i<=10001;i++) 43 { 44 if(!vi[i]) 45 { 46 printf("%d\n",i-1); 47 break; 48 } 49 } 50 return 0; 51 }
标签:main algo 内网 problems 必须 span 双向 最小 one
原文地址:http://www.cnblogs.com/liutianrui/p/7562839.html