落谷P1330封锁阳光大学 //图论,邻接表存无向图,bfs染色

http://www.luogu.org/problem/show?pid=1330

刚开始水图论,看题后根本没有思路,并且数据比较大,要用邻接表,以前从来没有实现过。。。

去看了看题解,才有了思路。

染色嘛,一层染一个颜色,即相邻节点染与当前节点不同的颜色,如121212.。。。如果对于一个节点的相邻节点曾经染过且与当前的颜色相同则不能完成染色。否则染色。

第一次写邻接表。。。查了半天资料,写了个还能看的,但是这是个无向图,傻b的我竟然不会23333,后来突然想到,两个点连两条边不就好了。。。2333。

bfs调了半天最后发现就是之前的加边函数 add 写的不对。。。改了以后过了样例,就高高兴兴的交,然后高高兴兴的wa了一半。又交了个Impossible,40分23333。白做了。

苦思不得解,看了看题解,嗯,多个联通块,每个都得计数,不能一起记。。。自己就傻。。一起数黑白点,然后取小的。。。。于是开了个桶,一边bfs一边计数。

嗯,过了

代码如下,注释很详细,毕竟第一次写邻接表,也算给自己存个模板,以后拿出来看看。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 #include<queue>
 7 #include<cstdlib>
 8 #include<algorithm>
 9 #define for1(i,n,m) for(int i=(n);i<=(m);i++)
10 #define for2(i,n,m) for(int i=(n);i>=(m);i--)
11 using namespace std;
12 int ans,n,m
13 int sum[10005];                //第i个点的边数 
14 int co[10005];                //第i个点的‘颜色’ 
15 int num=1;                    //边序号 
16 int woc[3];                    //每个联通块中的黑(woc[1]),白(woc[2])点的数量 
17 bool v[10005];
18 
19 int  node[10005];
20 struct edge
21 {
22     int from,next,to;        //e[i]表示第i条边,from起点,to终点,next下一条边 
23 }e[200005];                    //结构体数组模拟 邻接表,node[i]表示第i个点的第一条边, 
24 
25 queue <int> q;
26 
27 void add(int from,int to)    //增加一条from到to的边 
28 {
29     e[num].from=from;         
30     e[num].to=to;            //第num条边的起点是from,终点是to 
31     e[num].next=node[from];    //第num条边的下一条边是原来第from个点的第一条边 
32     node[from]=num;            //第from个点的第一条边更改为第num条边 
33     sum[from]++;            //这里是本题需要,第from个点的边数加1 
34     num++;                    //边的序号加1 
35 }
36 
37 void bfs(int qq)            //染色 
38 {
39     q.push(qq);
40     v[qq]=1;
41     co[qq]=1;
42     woc[1]++;
43     int tmp;
44     while(!q.empty())
45     {
46         int x=q.front();
47         q.pop();
48         tmp=co[x];
49         int x1,us;
50         us=node[x];
51         for1(i,1,sum[x])
52         {    
53             x1=e[us].to;
54             us=e[us].next;
55             if(co[x1]==tmp)    //与父亲节点的颜色一样则不可能。 
56             {    
57                 cout<<"Impossible";
58                 exit(0);    //直接退出程序。 
59             }
60             else if(!v[x1])
61             {
62                 q.push(x1);
63                 v[x1]=1;
64                 co[x1]=3-tmp;
65                 woc[co[x1]]++;
66             }
67    /*         else if(co[x1]==tmp)
68             {
69                 
70                 exit(0);
71             }  */  
72         }
73     
74     }
75 }
76 
77 int main()
78 {
79     cin>>n>>m;
80     int x,y;
81     for1(i,1,m)
82     {
83         cin>>x>>y;
84         add(x,y);
85         add(y,x);
86     }
87     for1(i,1,n)
88     {
89         if(!v[i])
90         {
91             bfs(i);
92             ans+=min(woc[1],woc[2]);//答案加上每个联通块的黑白点数少的。(重点,被坑了50) 
93         }
94         memset(woc,0,sizeof(woc));    //每个联通块的数目清空 
95     }
96     cout<<ans;
97     return 0;
98 }
View Code

 

转载于:https://www.cnblogs.com/WMYWMY/p/5775718.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值